diff --git a/docs/manual/about.html b/docs/manual/about.html deleted file mode 100644 index 3c1441c982..0000000000 --- a/docs/manual/about.html +++ /dev/null @@ -1,373 +0,0 @@ - - - - -About Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

About Otoroshi

-

At the beginning of 2017, we had the need to create a new environment to be able to create new “digital” products very quickly in an agile fashion at MAIF. Naturally we turned to PaaS solutions and chose the excellent Clever Cloud product to run our apps.

-

We also chose that every feature team will have the freedom to choose its own technological stack to build its product. It was a nice move but it has also introduced some challenges in terms of homogeneity for traceability, security, logging, … because we did not want to force library usage in the products. We could have used something like Service Mesh Pattern but the deployement model of Clever Cloud prevented us to do it.

-

The right solution was to use a reverse proxy or some kind of API Gateway able to provide tracability, logging, security with apikeys, quotas, DNS as a service locator, etc. We needed something easy to use, with a human friendly UI, a nice API to extends its features, true hot reconfiguration, able to generate internal events for third party usage. A couple of solutions were available at that time, but not one seems to fit our needs, there was always something missing, too complicated for our needs or not playing well with Clever Cloud deployment model.

-

At some point, we tried to write a small prototype to explore what could be our dream reverse proxy. The design was very simple, there were some rough edges but every major feature needed was there waiting to be enhanced.

-

Otoroshi was born and we decided to move ahead with our hairy monster :)

-

Philosophy

-

Every OSS product build at MAIF like the develoer portal Daikoku or Izanami follow a common philosophy.

-
    -
  • the services or API provided should be technology agnostic.
  • -
  • http first: http is the right answer to the previous quote
  • -
  • api First: the UI is just another client of the api.
  • -
  • secured: the services exposed need authentication for both humans or machines
  • -
  • event based: the services should expose a way to get notified of what happened inside.
  • -
- -
-
- -
-
- -
-
- -
- - - -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/api.html b/docs/manual/api.html deleted file mode 100644 index ce2f72c102..0000000000 --- a/docs/manual/api.html +++ /dev/null @@ -1,373 +0,0 @@ - - - - -Admin REST API · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Admin REST API

-

Otoroshi provides a fully featured REST admin API to perform almost every operation possible in the Otoroshi dashboard. The Otoroshi dashbaord is just a regular consumer of the admin API.

-

Using the admin API, you can do whatever you want and enhance your Otoroshi instances with a lot of features that will feet your needs.

-

Swagger descriptor

-

The Otoroshi admin API is described using OpenAPI format and is available at :

-

https://maif.github.io/otoroshi/manual/code/openapi.json

-

Every Otoroshi instance provides its own embedded OpenAPI descriptor at :

-

http://otoroshi.oto.tools:8080/api/openapi.json

-

Swagger documentation

-

You can read the OpenAPI descriptor in a more human friendly fashion using Swagger UI. The swagger UI documentation of the Otoroshi admin API is available at :

-

https://maif.github.io/otoroshi/swagger-ui/index.html

-

Every Otoroshi instance provides its own embedded OpenAPI descriptor at :

-

http://otoroshi.oto.tools:8080/api/swagger/ui

-

You can also read the swagger UI documentation of the Otoroshi admin API below :

- -
-
- -
-
- -
-
- -
- - - -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/architecture.html b/docs/manual/architecture.html deleted file mode 100644 index c2394b5395..0000000000 --- a/docs/manual/architecture.html +++ /dev/null @@ -1,352 +0,0 @@ - - - - -Architecture · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Architecture

-

When we started the development of Otoroshi, we had several classical patterns in mind like Service gateway, Service locator, Circuit breakers, etc …

-

At start we thought about providing a bunch of librairies that would be included in each microservice or app to perform these tasks. But the more we were thinking about it, the more it was feeling weird, unagile, etc, it also prevented us to use any technical stack we wanted to use. So we decided to change our approach to something more universal.

-

We chose to make Otoroshi the central part of our microservices system, something between a reverse-proxy, a service gateway and a service locator where each call to a microservice (even from another microservice) must pass through Otoroshi. There are multiple benefits to do that, each call can be logged, audited, monitored, integrated with a circuit breaker, etc without imposing libraries and technical stack. Any service is exposed through its own domain and we rely only on DNS to handle the service location part. Any access to a service is secured by default with an api key and is supervised by a circuit breaker to avoid cascading failures.

-
-

Otoroshi tries to embrace our global philosophy by providing a full featured REST admin api, a gorgeous admin dashboard written in React that uses the api, by generating traffic events, alerts events, audit events that can be consumed by several channels. Otoroshi also supports a bunch of datastores to better match with different use cases.

-
- -
-
-
-
- -
-
- -
- - - -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/code/openapi.json b/docs/manual/code/openapi.json deleted file mode 100644 index 92637948e2..0000000000 --- a/docs/manual/code/openapi.json +++ /dev/null @@ -1,28377 +0,0 @@ -{ - "openapi" : "3.0.3", - "info" : { - "title" : "Otoroshi Admin API", - "description" : "Admin API of the Otoroshi reverse proxy", - "version" : "1.5.11", - "contact" : { - "name" : "Otoroshi Team", - "email" : "oss@maif.fr" - }, - "license" : { - "name" : "Apache 2.0", - "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "externalDocs" : { - "url" : "https://www.otoroshi.io", - "description" : "everything about otoroshi" - }, - "servers" : [ { - "url" : "http://otoroshi-api.oto.tools:8080", - "description" : "your local otoroshi server" - } ], - "tags" : [ { - "name" : "admin-sessions", - "description" : "All api endpoints about admin-session" - }, { - "name" : "admins", - "description" : "All api endpoints about admins" - }, { - "name" : "analytics", - "description" : "All api endpoints about analytics" - }, { - "name" : "apikeys", - "description" : "All api endpoints about apikeys" - }, { - "name" : "apps-sessions", - "description" : "All api endpoints about apps-sessions" - }, { - "name" : "auth-modules", - "description" : "All api endpoints about auth-modules" - }, { - "name" : "certificates", - "description" : "All api endpoints about certificates" - }, { - "name" : "cluster", - "description" : "All api endpoints about cluster" - }, { - "name" : "data-exporters", - "description" : "All api endpoints about data-exporters" - }, { - "name" : "events", - "description" : "All api endpoints about events" - }, { - "name" : "experimental", - "description" : "All experimental endpoints" - }, { - "name" : "globalconfig", - "description" : "All api endpoints about globalconfig" - }, { - "name" : "groups", - "description" : "All api endpoints about groups" - }, { - "name" : "import-export", - "description" : "All api endpoints about import-export" - }, { - "name" : "jwt-verifiers", - "description" : "All api endpoints about jwt-verifiers" - }, { - "name" : "lines", - "description" : "All api endpoints about lines" - }, { - "name" : "live", - "description" : "All api endpoints about live" - }, { - "name" : "organizations", - "description" : "All api endpoints about organizations" - }, { - "name" : "pki", - "description" : "All api endpoints about pki" - }, { - "name" : "privateapps", - "description" : "All api endpoints about privateapps" - }, { - "name" : "scripts", - "description" : "All api endpoints about scripts" - }, { - "name" : "services", - "description" : "All api endpoints about services" - }, { - "name" : "snowmonkey", - "description" : "All api endpoints about snowmonkey" - }, { - "name" : "tcp", - "description" : "All api endpoints about tcp" - }, { - "name" : "teams", - "description" : "All api endpoints about teams" - }, { - "name" : "templates", - "description" : "All api endpoints about templates " - } ], - "paths" : { - "/api/stats" : { - "get" : { - "tags" : [ "analytics" ], - "summary" : "Statistic for a service, apikey or group", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.filterableStats", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/stats/global" : { - "get" : { - "tags" : [ "analytics" ], - "summary" : "Global statistic for your services", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.globalStats", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/services/{serviceId}/stats" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Statistics for a service", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.serviceStats", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/scripts/_template" : { - "get" : { - "tags" : [ "scripts" ], - "summary" : "Creates a new Script from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateScript", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - } - }, - "/api/scripts/_list" : { - "get" : { - "tags" : [ "scripts" ], - "summary" : "Search plugins based on type of plugin", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.findAllScriptsList", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ScriptsList" - } - } - } - } - } - } - }, - "/api/admins/webauthn" : { - "post" : { - "tags" : [ "admins" ], - "summary" : "Register a webauthn admin user", - "operationId" : "otoroshi.controllers.adminapi.UsersController.registerWebAuthnAdmin", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } - } - } - } - }, - "get" : { - "tags" : [ "admins" ], - "summary" : "Returns all webauthn admin", - "operationId" : "otoroshi.controllers.adminapi.UsersController.webAuthnAdmins", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/WebauthnAdminList" - } - } - } - } - } - } - }, - "/api/groups/{groupId}/status" : { - "get" : { - "tags" : [ "groups" ], - "summary" : "Statis for a group of services over time", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.groupStatus", - "parameters" : [ { - "name" : "groupId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the groupId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/teams/{id}" : { - "patch" : { - "tags" : [ "teams" ], - "summary" : "Updates (using json-patch) a specific Team using its id", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - }, - "get" : { - "tags" : [ "teams" ], - "summary" : "Find a specific Team using its id", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "teams" ], - "summary" : "Deletes a specific Team using its id", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - }, - "put" : { - "tags" : [ "teams" ], - "summary" : "Updates a specific Team using its id", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - }, - "/api/teams" : { - "post" : { - "tags" : [ "teams" ], - "summary" : "Creates a Team", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - }, - "get" : { - "tags" : [ "teams" ], - "summary" : "Find all possible Teams entities", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - } - } - }, - "/api/teams/_bulk" : { - "patch" : { - "tags" : [ "teams" ], - "summary" : "Update (using json-patch) multiple Teams at the same time", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "teams" ], - "summary" : "Create multiple Teams at the same time", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "teams" ], - "summary" : "Delete multiple Teams at the same time", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "teams" ], - "summary" : "Update multiple Teams at the same time", - "operationId" : "otoroshi.controllers.adminapi.TeamsController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - } - }, - "/api/services/{serviceId}/targets" : { - "patch" : { - "tags" : [ "services" ], - "summary" : "Update the target of the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.updateServiceTargets", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - } - } - } - } - }, - "post" : { - "tags" : [ "services" ], - "summary" : "Adds a target to the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.serviceAddTarget", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - } - } - } - } - }, - "get" : { - "tags" : [ "services" ], - "summary" : "Get targets of the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.serviceTargets", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/TargetsList" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "services" ], - "summary" : "Deletes a target to the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.serviceDeleteTarget", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/experimental/forms" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Return all plugins config form spec", - "operationId" : "otoroshi.next.controllers.NgPluginsController.forms", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/auths/{id}" : { - "patch" : { - "tags" : [ "auth-modules" ], - "summary" : "Updates (using json-patch) a specific AuthModuleConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - }, - "get" : { - "tags" : [ "auth-modules" ], - "summary" : "Find a specific AuthModuleConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "auth-modules" ], - "summary" : "Deletes a specific AuthModuleConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - }, - "put" : { - "tags" : [ "auth-modules" ], - "summary" : "Updates a specific AuthModuleConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - }, - "/api/experimental/routes/_form" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "The form description of the current controllers entity", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ExperimentalFormResponse" - } - } - } - } - } - } - }, - "/api/cluster/members" : { - "get" : { - "tags" : [ "cluster" ], - "summary" : "Get cluster members statistics", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.getClusterMembers", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "cluster" ], - "summary" : "Clear cluster members from members statistics", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.clearClusterMembers", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/experimental/services/_form" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "The form description of the current controllers entity", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ExperimentalFormResponse" - } - } - } - } - } - } - }, - "/api/experimental/targets/_template" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Creates a new template for a target", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.initiateStoredNgTarget", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - } - }, - "/api/auths/_bulk" : { - "patch" : { - "tags" : [ "auth-modules" ], - "summary" : "Update (using json-patch) multiple AuthModuleConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "auth-modules" ], - "summary" : "Create multiple AuthModuleConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "auth-modules" ], - "summary" : "Delete multiple AuthModuleConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "auth-modules" ], - "summary" : "Update multiple AuthModuleConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - } - }, - "/api/experimental/plugins/categories" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Returns all possible plugins categories", - "operationId" : "otoroshi.next.controllers.NgPluginsController.categories", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/StringList" - } - } - } - } - } - } - }, - "/api/scripts" : { - "post" : { - "tags" : [ "scripts" ], - "summary" : "Creates a otoroshi.script.Script", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - }, - "get" : { - "tags" : [ "scripts" ], - "summary" : "Find all possible otoroshi.script.Scripts entities", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - } - } - }, - "/api/privateapps/sessions/{id}/{username}" : { - "post" : { - "tags" : [ "privateapps" ], - "summary" : "Registers a private app session", - "operationId" : "otoroshi.controllers.PrivateAppsController.registerSession", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - }, { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/cluster/sessions/{id}" : { - "get" : { - "tags" : [ "cluster" ], - "summary" : "Api to create a distributed private apps session between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.isSessionValid", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.PrivateAppsUser" - } - } - } - } - } - } - }, - "/api/apikeys/_bulk" : { - "patch" : { - "tags" : [ "apikeys" ], - "summary" : "Update (using json-patch) multiple ApiKeys at the same time", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "apikeys" ], - "summary" : "Create multiple ApiKeys at the same time", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "apikeys" ], - "summary" : "Delete multiple ApiKeys at the same time", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "apikeys" ], - "summary" : "Update multiple ApiKeys at the same time", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - } - }, - "/api/apps-sessions/{id}" : { - "delete" : { - "tags" : [ "apps-sessions" ], - "summary" : "Discard a specific private apps session", - "operationId" : "otoroshi.controllers.adminapi.UsersController.discardPrivateAppsSession", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/services" : { - "post" : { - "tags" : [ "services" ], - "summary" : "Creates a ServiceDescriptor", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - }, - "get" : { - "tags" : [ "services" ], - "summary" : "Find all possible ServiceDescriptors entities", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - } - } - }, - "/api/tenants" : { - "post" : { - "tags" : [ "organizations" ], - "summary" : "Creates a Tenant", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - }, - "get" : { - "tags" : [ "organizations" ], - "summary" : "Find all possible Tenants entities", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - } - } - }, - "/api/new/service" : { - "get" : { - "tags" : [ "templates" ], - "summary" : "Creates a new Service from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateService_templates", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - } - }, - "/api/snowmonkey/config" : { - "patch" : { - "tags" : [ "snowmonkey" ], - "summary" : "Updates (using json-patch) the snowmonkey configuration", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.patchSnowMonkey", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SnowMonkeyConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/PatchBody" - } - } - } - } - }, - "get" : { - "tags" : [ "snowmonkey" ], - "summary" : "Get the snowmonkey config", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.getSnowMonkeyConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SnowMonkeyConfig" - } - } - } - } - } - }, - "put" : { - "tags" : [ "snowmonkey" ], - "summary" : "Updates the snowmonkey configuration", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.updateSnowMonkey", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SnowMonkeyConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SnowMonkeyConfig" - } - } - } - } - } - }, - "/api/globalconfig/_template" : { - "get" : { - "tags" : [ "globalconfig" ], - "summary" : "Creates a new GlobalConfig from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateGlobalConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - } - } - } - } - } - } - }, - "/api/alert/events" : { - "get" : { - "tags" : [ "events" ], - "summary" : "Get all events of type AlertEvent", - "operationId" : "otoroshi.controllers.adminapi.EventsController.alertEvents", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/AlertEventList" - } - } - } - } - } - } - }, - "/api/lines/{line}/services" : { - "get" : { - "tags" : [ "lines" ], - "summary" : "Get all service for a line of work", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.servicesForALine", - "parameters" : [ { - "name" : "line", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The line param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ServiceDescriptorList" - } - } - } - } - } - } - }, - "/api/experimental/backends/_bulk" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Update (using json-patch) multiple StoredNgBackends at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "experimental" ], - "summary" : "Create multiple StoredNgBackends at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Delete multiple StoredNgBackends at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Update multiple StoredNgBackends at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - } - }, - "/api/experimental/services/{id}" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Updates (using json-patch) a specific NgService using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find a specific NgService using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Deletes a specific NgService using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Updates a specific NgService using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - }, - "/api/groups" : { - "post" : { - "tags" : [ "groups" ], - "summary" : "Creates a ServiceGroup", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - }, - "get" : { - "tags" : [ "groups" ], - "summary" : "Find all possible ServiceGroups entities", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - } - } - }, - "/api/experimental/plugins/steps" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Returns all possible plugins steps", - "operationId" : "otoroshi.next.controllers.NgPluginsController.steps", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/StringList" - } - } - } - } - } - } - }, - "/api/{entity}/_template" : { - "post" : { - "tags" : [ "templates" ], - "summary" : "Creates a new Template from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.createFromTemplate_templates", - "parameters" : [ { - "name" : "entity", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the entity parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/experimental/targets/{id}" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Updates (using json-patch) a specific StoredNgTarget using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find a specific StoredNgTarget using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Deletes a specific StoredNgTarget using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Updates a specific StoredNgTarget using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - }, - "/api/pki/cas/{ca}/cas" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a sub-CA", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genSubCA", - "parameters" : [ { - "name" : "ca", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the ca parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } - } - } - } - } - }, - "/api/verifiers/{id}" : { - "patch" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Updates (using json-patch) a specific GlobalJwtVerifier using its id", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - }, - "get" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Find a specific GlobalJwtVerifier using its id", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Deletes a specific GlobalJwtVerifier using its id", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - }, - "put" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Updates a specific GlobalJwtVerifier using its id", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - }, - "/api/experimental/backends/_template" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Generates a new backend template", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.initiateStoredNgBackend", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - } - }, - "/api/admin-sessions/{id}" : { - "delete" : { - "tags" : [ "admin-sessions" ], - "summary" : "Discard a specific admin session (otoroshi-ui)", - "operationId" : "otoroshi.controllers.adminapi.UsersController.discardSession", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/tcp/_template" : { - "get" : { - "tags" : [ "tcp" ], - "summary" : "Creates a new TcpService from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateTcpService_tcp", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - } - }, - "/api/status/global" : { - "get" : { - "tags" : [ "analytics" ], - "summary" : "Global status of your services", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.globalStatus", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/services/_bulk" : { - "patch" : { - "tags" : [ "services" ], - "summary" : "Update (using json-patch) multiple ServiceDescriptors at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "services" ], - "summary" : "Create multiple ServiceDescriptors at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "services" ], - "summary" : "Delete multiple ServiceDescriptors at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "services" ], - "summary" : "Update multiple ServiceDescriptors at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - } - }, - "/api/snowmonkey/outages" : { - "get" : { - "tags" : [ "snowmonkey" ], - "summary" : "Get the current snowmonkey outages", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.getSnowMonkeyOutages", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/OutagesList" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "snowmonkey" ], - "summary" : "Reset the snowmonkey outages", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.resetSnowMonkey", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/data-exporter-configs/_bulk" : { - "patch" : { - "tags" : [ "data-exporters" ], - "summary" : "Update (using json-patch) multiple DataExporterConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "data-exporters" ], - "summary" : "Create multiple DataExporterConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "data-exporters" ], - "summary" : "Delete multiple DataExporterConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "data-exporters" ], - "summary" : "Update multiple DataExporterConfigs at the same time", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - } - }, - "/api/experimental/services/_template" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Creates a new template for a service", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.initiateService", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - } - }, - "/api/tenants/_bulk" : { - "patch" : { - "tags" : [ "organizations" ], - "summary" : "Update (using json-patch) multiple Tenants at the same time", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "organizations" ], - "summary" : "Create multiple Tenants at the same time", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "organizations" ], - "summary" : "Delete multiple Tenants at the same time", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "organizations" ], - "summary" : "Update multiple Tenants at the same time", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - } - }, - "/api/certificates/_bundle" : { - "post" : { - "tags" : [ "certificates" ], - "summary" : "Import PEM bundle as otoroshi certificates", - "operationId" : "otoroshi.controllers.adminapi.PkiController.importBundle", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/PemCertificateBody" - } - } - } - } - } - }, - "/api/cluster/state" : { - "get" : { - "tags" : [ "cluster" ], - "summary" : "Api to get internal state from a leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.internalState", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - } - }, - "/api/new/resources" : { - "post" : { - "tags" : [ "templates" ], - "summary" : "Creates a new Resources from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateResources", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - }, - "/api/pki/certs/_p12" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Import de .p12 file as client certificates", - "operationId" : "otoroshi.controllers.adminapi.PkiController.importCertFromP12", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ByteStreamBody" - } - } - } - } - } - }, - "/api/pki/keys" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a keypair", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genKeyPair", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenKeyPairResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenKeyPairQuery" - } - } - } - } - } - }, - "/api/experimental/targets/_form" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "The form description of the current controllers entity", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ExperimentalFormResponse" - } - } - } - } - } - } - }, - "/api/otoroshi.json" : { - "post" : { - "tags" : [ "import-export" ], - "summary" : "Import the content of the otoroshi datastore (json)", - "operationId" : "otoroshi.controllers.adminapi.ImportExportController.fullImport", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfigImportBody" - } - } - } - } - }, - "get" : { - "tags" : [ "import-export" ], - "summary" : "Export all the content of the otoroshi datastore", - "operationId" : "otoroshi.controllers.adminapi.ImportExportController.fullExport", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - } - }, - "/api/auths" : { - "post" : { - "tags" : [ "auth-modules" ], - "summary" : "Creates a AuthModuleConfig", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - }, - "get" : { - "tags" : [ "auth-modules" ], - "summary" : "Find all possible AuthModuleConfigs entities", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - } - } - }, - "/api/admins/webauthn/_template" : { - "post" : { - "tags" : [ "admins" ], - "summary" : "Creates a new Template from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.createFromTemplate_webauthn", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.OtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - }, - "get" : { - "tags" : [ "admins" ], - "summary" : "Creates a new WebauthnAdmin from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateWebauthnAdmin", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - } - } - }, - "/api/groups/{id}" : { - "patch" : { - "tags" : [ "groups" ], - "summary" : "Updates (using json-patch) a specific ServiceGroup using its id", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - }, - "get" : { - "tags" : [ "groups" ], - "summary" : "Find a specific ServiceGroup using its id", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "groups" ], - "summary" : "Deletes a specific ServiceGroup using its id", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - }, - "put" : { - "tags" : [ "groups" ], - "summary" : "Updates a specific ServiceGroup using its id", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - }, - "/api/tenants/{id}" : { - "patch" : { - "tags" : [ "organizations" ], - "summary" : "Updates (using json-patch) a specific Tenant using its id", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - }, - "get" : { - "tags" : [ "organizations" ], - "summary" : "Find a specific Tenant using its id", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "organizations" ], - "summary" : "Deletes a specific Tenant using its id", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - }, - "put" : { - "tags" : [ "organizations" ], - "summary" : "Updates a specific Tenant using its id", - "operationId" : "otoroshi.controllers.adminapi.TenantsController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - }, - "/api/live" : { - "get" : { - "tags" : [ "live" ], - "summary" : "Get global live statis", - "operationId" : "otoroshi.controllers.adminapi.StatsController.globalLiveStats", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/LiveStats" - } - } - } - } - } - } - }, - "/api/experimental/backends/{id}" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Updates (using json-patch) a specific StoredNgBackend using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find a specific StoredNgBackend using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Deletes a specific StoredNgBackend using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Updates a specific StoredNgBackend using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - }, - "/api/experimental/routes/{id}" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Updates (using json-patch) a specific NgRoute using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find a specific NgRoute using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Deletes a specific NgRoute using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Updates a specific NgRoute using its id", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - }, - "/api/experimental/frontends/_form" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "The form description of the current controllers entity", - "operationId" : "otoroshi.next.controllers.adminapi.NgFrontendsController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ExperimentalFormResponse" - } - } - } - } - } - } - }, - "/api/admins/webauthn/{username}/{id}" : { - "delete" : { - "tags" : [ "admins" ], - "summary" : "Deletes a webauthn admin", - "operationId" : "otoroshi.controllers.adminapi.UsersController.webAuthnDeleteAdmin", - "parameters" : [ { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - }, { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/experimental/routes" : { - "post" : { - "tags" : [ "experimental" ], - "summary" : "Creates a NgRoute", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find all possible NgRoutes entities", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - } - } - }, - "/api/import" : { - "post" : { - "tags" : [ "import-export" ], - "summary" : "Import the content of the otoroshi datastore (file)", - "operationId" : "otoroshi.controllers.adminapi.ImportExportController.fullImportFromFile", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfigImportBody" - } - } - } - } - } - }, - "/api/pki/cas" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a self signed CA", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genSelfSignedCA", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } - } - } - } - } - }, - "/api/scripts/{id}" : { - "patch" : { - "tags" : [ "scripts" ], - "summary" : "Updates (using json-patch) a specific otoroshi.script.Script using its id", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - }, - "get" : { - "tags" : [ "scripts" ], - "summary" : "Find a specific otoroshi.script.Script using its id", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "scripts" ], - "summary" : "Deletes a specific otoroshi.script.Script using its id", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - }, - "put" : { - "tags" : [ "scripts" ], - "summary" : "Updates a specific otoroshi.script.Script using its id", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - }, - "/api/events" : { - "get" : { - "tags" : [ "analytics" ], - "summary" : "Events for a service, apikey or group", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.filterableEvents", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/pki/certs" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a self signed certificates", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genSelfSignedCert", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } - } - } - } - } - }, - "/api/new/tcp/service" : { - "get" : { - "tags" : [ "templates" ], - "summary" : "Creates a new TcpService from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateTcpService_templates", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - } - }, - "/api/auths/{id}/register/finish" : { - "post" : { - "tags" : [ "auth-modules" ], - "summary" : "Finishes the registration of a user", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.finishRegistration", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/WebAuthnRegistrationFinishBody" - } - } - } - } - } - }, - "/api/new/group" : { - "get" : { - "tags" : [ "templates" ], - "summary" : "Creates a new ServiceGroup from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateServiceGroup_templates", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - } - }, - "/api/tcp/services/_template" : { - "post" : { - "tags" : [ "tcp" ], - "summary" : "Creates a new Template from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.createFromTemplate_tcp", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/tcp/services/_bulk" : { - "patch" : { - "tags" : [ "tcp" ], - "summary" : "Update (using json-patch) multiple TcpServices at the same time", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "tcp" ], - "summary" : "Create multiple TcpServices at the same time", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "tcp" ], - "summary" : "Delete multiple TcpServices at the same time", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "tcp" ], - "summary" : "Update multiple TcpServices at the same time", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - } - }, - "/api/auths/_template" : { - "get" : { - "tags" : [ "auth-modules" ], - "summary" : "Creates a new AuthModule from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateAuthModule", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - } - } - } - } - } - } - }, - "/api/tcp/services" : { - "post" : { - "tags" : [ "tcp" ], - "summary" : "Creates a TcpService", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "get" : { - "tags" : [ "tcp" ], - "summary" : "Find all possible TcpServices entities", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - } - } - }, - "/api/verifiers/_template" : { - "get" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Creates a new JwtVerifier from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateJwtVerifier", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - } - }, - "/api/globalconfig" : { - "patch" : { - "tags" : [ "globalconfig" ], - "summary" : "Update (with json-patch) the global config", - "operationId" : "otoroshi.controllers.adminapi.GlobalConfigController.patchGlobalConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/PatchBody" - } - } - } - } - }, - "get" : { - "tags" : [ "globalconfig" ], - "summary" : "Get the global config", - "operationId" : "otoroshi.controllers.adminapi.GlobalConfigController.globalConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - } - } - } - } - } - }, - "put" : { - "tags" : [ "globalconfig" ], - "summary" : "Update the global config", - "operationId" : "otoroshi.controllers.adminapi.GlobalConfigController.updateGlobalConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - } - } - } - } - } - }, - "/api/services/{serviceId}/response" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Response time statistics for a service", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.serviceResponseTime", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/new/apikey" : { - "get" : { - "tags" : [ "templates" ], - "summary" : "Creates a new ApiKey from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateApiKey_templates", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - } - }, - "/api/apikeys/{id}" : { - "patch" : { - "tags" : [ "apikeys" ], - "summary" : "Updates (using json-patch) a specific ApiKey using its id", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - }, - "get" : { - "tags" : [ "apikeys" ], - "summary" : "Find a specific ApiKey using its id", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "apikeys" ], - "summary" : "Deletes a specific ApiKey using its id", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - }, - "put" : { - "tags" : [ "apikeys" ], - "summary" : "Updates a specific ApiKey using its id", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - }, - "/api/pki/certs/_data" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Extract data from a certificate", - "operationId" : "otoroshi.controllers.adminapi.PkiController.certificateData", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/PemCertificateBody" - } - } - } - } - } - }, - "/api/cluster/quotas" : { - "put" : { - "tags" : [ "cluster" ], - "summary" : "Api to push quotas usage from a worker to a leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.updateQuotas", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/UpdateQuotasBody" - } - } - } - } - } - }, - "/api/admins/webauthn/{username}" : { - "put" : { - "tags" : [ "admins" ], - "summary" : "Updates a webauthn admin", - "operationId" : "otoroshi.controllers.adminapi.UsersController.updateWebAuthnAdmin", - "parameters" : [ { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } - } - } - } - } - }, - "/api/groups/_bulk" : { - "patch" : { - "tags" : [ "groups" ], - "summary" : "Update (using json-patch) multiple ServiceGroups at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "groups" ], - "summary" : "Create multiple ServiceGroups at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "groups" ], - "summary" : "Delete multiple ServiceGroups at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "groups" ], - "summary" : "Update multiple ServiceGroups at the same time", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - } - }, - "/api/experimental/backends/_form" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "The form description of the current controllers entity", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ExperimentalFormResponse" - } - } - } - } - } - } - }, - "/api/experimental/services" : { - "post" : { - "tags" : [ "experimental" ], - "summary" : "Creates a NgService", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find all possible NgServices entities", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - } - } - }, - "/api/services/{serviceId}/live" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Get live stats for a specific service", - "operationId" : "otoroshi.controllers.adminapi.StatsController.serviceLiveStats_services", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/LiveStats" - } - } - } - } - } - } - }, - "/api/experimental/services/_bulk" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Update (using json-patch) multiple NgServices at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "experimental" ], - "summary" : "Create multiple NgServices at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Delete multiple NgServices at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Update multiple NgServices at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - } - } - }, - "/api/scripts/_bulk" : { - "patch" : { - "tags" : [ "scripts" ], - "summary" : "Update (using json-patch) multiple otoroshi.script.Scripts at the same time", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "scripts" ], - "summary" : "Create multiple otoroshi.script.Scripts at the same time", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "scripts" ], - "summary" : "Delete multiple otoroshi.script.Scripts at the same time", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "scripts" ], - "summary" : "Update multiple otoroshi.script.Scripts at the same time", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - } - } - } - } - } - }, - "/api/data-exporter-configs/{id}" : { - "patch" : { - "tags" : [ "data-exporters" ], - "summary" : "Updates (using json-patch) a specific DataExporterConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - }, - "get" : { - "tags" : [ "data-exporters" ], - "summary" : "Find a specific DataExporterConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "data-exporters" ], - "summary" : "Deletes a specific DataExporterConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - }, - "put" : { - "tags" : [ "data-exporters" ], - "summary" : "Updates a specific DataExporterConfig using its id", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - }, - "/api/pki/csrs" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a CSR", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genCsr", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } - } - } - } - } - }, - "/api/groups/_template" : { - "get" : { - "tags" : [ "groups" ], - "summary" : "Creates a new ServiceGroup from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateServiceGroup_groups", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - } - } - } - } - } - } - }, - "/api/verifiers" : { - "post" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Creates a GlobalJwtVerifier", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - }, - "get" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Find all possible GlobalJwtVerifiers entities", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - } - } - }, - "/api/admins/simple/{username}" : { - "delete" : { - "tags" : [ "admins" ], - "summary" : "Deletes an admin", - "operationId" : "otoroshi.controllers.adminapi.UsersController.deleteAdmin", - "parameters" : [ { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - }, - "put" : { - "tags" : [ "admins" ], - "summary" : "Updates an admin", - "operationId" : "otoroshi.controllers.adminapi.UsersController.updateAdmin", - "parameters" : [ { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - } - }, - "/api/data-exporter-configs" : { - "post" : { - "tags" : [ "data-exporters" ], - "summary" : "Creates a DataExporterConfig", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - }, - "get" : { - "tags" : [ "data-exporters" ], - "summary" : "Find all possible DataExporterConfigs entities", - "operationId" : "otoroshi.controllers.adminapi.DataExporterConfigController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - } - } - }, - "/api/data-exporter-configs/_template" : { - "get" : { - "tags" : [ "data-exporters" ], - "summary" : "Creates a new DataExporterConfig from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateDataExporterConfig", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - } - } - } - } - } - } - }, - "/api/experimental/routes/_template" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Creates a new template for a route", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.initiateRoute", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - } - }, - "/api/teams/_template" : { - "get" : { - "tags" : [ "teams" ], - "summary" : "Creates a new Team from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateTeam", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - } - } - } - } - } - } - }, - "/api/admin-sessions" : { - "get" : { - "tags" : [ "admin-sessions" ], - "summary" : "Returns all admin sessions", - "operationId" : "otoroshi.controllers.adminapi.UsersController.sessions", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.BackOfficeUser" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "admin-sessions" ], - "summary" : "Discard all admin sessions (otoroshi-ui)", - "operationId" : "otoroshi.controllers.adminapi.UsersController.discardAllSessions", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/admins/simple/_template" : { - "post" : { - "tags" : [ "admins" ], - "summary" : "Creates a new Template from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.createFromTemplate_simple", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.OtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - }, - "get" : { - "tags" : [ "admins" ], - "summary" : "Creates a new SimpleAdmin from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateSimpleAdmin", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - } - } - }, - "/api/certificates/{id}" : { - "patch" : { - "tags" : [ "certificates" ], - "summary" : "Updates (using json-patch) a specific Cert using its id", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "get" : { - "tags" : [ "certificates" ], - "summary" : "Find a specific Cert using its id", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "certificates" ], - "summary" : "Deletes a specific Cert using its id", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - }, - "put" : { - "tags" : [ "certificates" ], - "summary" : "Updates a specific Cert using its id", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - }, - "/api/cluster/user-tokens/{id}" : { - "get" : { - "tags" : [ "cluster" ], - "summary" : "Api to get a distributed login token between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.getUserToken", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TokenResponse" - } - } - } - } - } - } - }, - "/api/snowmonkey/_start" : { - "post" : { - "tags" : [ "snowmonkey" ], - "summary" : "Start the snowmonkey of all otoroshi instances", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.startSnowMonkey", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/experimental/plugins/all" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Return all plugins descriptions", - "operationId" : "otoroshi.next.controllers.NgPluginsController.plugins", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/events/_template" : { - "get" : { - "tags" : [ "analytics" ], - "summary" : "Returns a template that extract possible fields out of a Gateway event", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.templateSpec", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - } - }, - "/api/services/{id}" : { - "patch" : { - "tags" : [ "services" ], - "summary" : "Updates (using json-patch) a specific ServiceDescriptor using its id", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - }, - "get" : { - "tags" : [ "services" ], - "summary" : "Find a specific ServiceDescriptor using its id", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "services" ], - "summary" : "Deletes a specific ServiceDescriptor using its id", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - }, - "put" : { - "tags" : [ "services" ], - "summary" : "Updates a specific ServiceDescriptor using its id", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - }, - "/api/apikeys" : { - "post" : { - "tags" : [ "apikeys" ], - "summary" : "Creates a ApiKey", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - }, - "get" : { - "tags" : [ "apikeys" ], - "summary" : "Find all possible ApiKeys entities", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - } - } - }, - "/api/pki/cas/{ca}/certs" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a certificate", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genCert", - "parameters" : [ { - "name" : "ca", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the ca parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } - } - } - } - } - }, - "/api/services/{serviceId}/events" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Events for a service", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.serviceEvents", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/certificates/_template" : { - "get" : { - "tags" : [ "certificates" ], - "summary" : "Creates a new Certificate from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateCertificate", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - } - }, - "/api/audit/events" : { - "get" : { - "tags" : [ "events" ], - "summary" : "Get all events of type AuditEvent", - "operationId" : "otoroshi.controllers.adminapi.EventsController.auditEvents", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/AuditEventList" - } - } - } - } - } - } - }, - "/api/snowmonkey/_stop" : { - "post" : { - "tags" : [ "snowmonkey" ], - "summary" : "Stop the snowmonkey of all otoroshi instances", - "operationId" : "otoroshi.controllers.adminapi.SnowMonkeyController.stopSnowMonkey", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/experimental/forms/_single" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Return a plugin config form spec", - "operationId" : "otoroshi.next.controllers.NgPluginsController.form", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/certificates/_bulk" : { - "patch" : { - "tags" : [ "certificates" ], - "summary" : "Update (using json-patch) multiple Certs at the same time", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "certificates" ], - "summary" : "Create multiple Certs at the same time", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "certificates" ], - "summary" : "Delete multiple Certs at the same time", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "certificates" ], - "summary" : "Update multiple Certs at the same time", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - } - }, - "/api/tenants/_template" : { - "get" : { - "tags" : [ "organizations" ], - "summary" : "Creates a new Tenant from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateTenant", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - } - } - } - } - } - } - }, - "/api/services/{serviceId}/health" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Get healthcheck status for the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.serviceHealth", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/HealthCheckEventList" - } - } - } - } - } - } - }, - "/api/services/{serviceId}/canary" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Get members of a canary campaign", - "operationId" : "otoroshi.controllers.adminapi.CanaryController.serviceCanaryMembers", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "services" ], - "summary" : "Reset members of a canary campaign", - "operationId" : "otoroshi.controllers.adminapi.CanaryController.resetServiceCanaryMembers", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/live/host" : { - "get" : { - "tags" : [ "live" ], - "summary" : "Get local host metrics", - "operationId" : "otoroshi.controllers.adminapi.StatsController.hostMetrics", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/HostMetrics" - } - } - } - } - } - } - }, - "/api/pki/certs/_valid" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Check if a certificate is valid (based on its own data)", - "operationId" : "otoroshi.controllers.adminapi.PkiController.certificateIsValid", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/CertValidResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - }, - "/api/cluster/live" : { - "get" : { - "tags" : [ "cluster" ], - "summary" : "Api to get cluster statistics", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.liveCluster", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - } - } - }, - "/api/certificates" : { - "post" : { - "tags" : [ "certificates" ], - "summary" : "Creates a Cert", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "get" : { - "tags" : [ "certificates" ], - "summary" : "Find all possible Certs entities", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - } - } - } - }, - "/api/apikeys/{id}/quotas" : { - "get" : { - "tags" : [ "apikeys" ], - "summary" : "Consumed quotas for a specific apikey", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.apiKeyQuotas", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.RemainingQuotas" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "apikeys" ], - "summary" : "Reset quotas consumption for an apikey", - "operationId" : "otoroshi.controllers.adminapi.ApiKeysController.resetApiKeyQuotas", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.RemainingQuotas" - } - } - } - } - } - } - }, - "/api/cluster/user-tokens" : { - "post" : { - "tags" : [ "cluster" ], - "summary" : "Api to set a distributed login token between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.setUserToken", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TokenResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/UserTokenBody" - } - } - } - } - } - }, - "/api/pki/certs/_letencrypt" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Generates a certificates using Let's Encrypt or any ACME compatible system", - "operationId" : "otoroshi.controllers.adminapi.PkiController.genLetsEncryptCert", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/LetsEncryptCertBody" - } - } - } - } - } - }, - "/api/live/{id}" : { - "get" : { - "tags" : [ "live" ], - "summary" : "Get live stats for a specific service", - "operationId" : "otoroshi.controllers.adminapi.StatsController.serviceLiveStats_live", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/LiveStats" - } - } - } - } - } - } - }, - "/api/verifiers/_bulk" : { - "patch" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Update (using json-patch) multiple GlobalJwtVerifiers at the same time", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Create multiple GlobalJwtVerifiers at the same time", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Delete multiple GlobalJwtVerifiers at the same time", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "jwt-verifiers" ], - "summary" : "Update multiple GlobalJwtVerifiers at the same time", - "operationId" : "otoroshi.controllers.adminapi.JwtVerifierController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - } - } - } - } - } - } - }, - "/api/lines" : { - "get" : { - "tags" : [ "lines" ], - "summary" : "Get all lines of work (prod, preprod, etc)", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.allLines", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/StringList" - } - } - } - } - } - } - }, - "/api/apps-sessions" : { - "get" : { - "tags" : [ "apps-sessions" ], - "summary" : "Return all private apps sessions", - "operationId" : "otoroshi.controllers.adminapi.UsersController.privateAppsSessions", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.PrivateAppsUser" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "apps-sessions" ], - "summary" : "Discard all private apps sessions", - "operationId" : "otoroshi.controllers.adminapi.UsersController.discardAllPrivateAppsSessions", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - } - }, - "/api/apikeys/_template" : { - "get" : { - "tags" : [ "apikeys" ], - "summary" : "Creates a new ApiKey from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateApiKey_apikeys", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - } - } - } - } - }, - "/api/experimental/backends" : { - "post" : { - "tags" : [ "experimental" ], - "summary" : "Creates a StoredNgBackend", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find all possible StoredNgBackends entities", - "operationId" : "otoroshi.next.controllers.adminapi.NgBackendsController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - } - } - } - } - } - } - } - }, - "/api/experimental/routes/_bulk" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Update (using json-patch) multiple NgRoutes at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "experimental" ], - "summary" : "Create multiple NgRoutes at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Delete multiple NgRoutes at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Update multiple NgRoutes at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - } - } - } - } - } - } - }, - "/api/groups/{id}/services" : { - "get" : { - "tags" : [ "groups" ], - "summary" : "Get the services from a service group", - "operationId" : "otoroshi.controllers.adminapi.ServiceGroupController.serviceGroupServices", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ServiceDescriptorList" - } - } - } - } - } - } - }, - "/api/experimental/targets" : { - "post" : { - "tags" : [ "experimental" ], - "summary" : "Creates a StoredNgTarget", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.createAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "201" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - }, - "get" : { - "tags" : [ "experimental" ], - "summary" : "Find all possible StoredNgTargets entities", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.findAllEntitiesAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - } - } - }, - "/api/services/{serviceId}/template" : { - "post" : { - "tags" : [ "services" ], - "summary" : "Creates an error template for the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.createServiceTemplate", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" - } - } - } - } - }, - "get" : { - "tags" : [ "services" ], - "summary" : "Get the error template for the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.serviceTemplate", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplateList" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "services" ], - "summary" : "Deletes the error template for the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.deleteServiceTemplate", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - } - }, - "put" : { - "tags" : [ "services" ], - "summary" : "Update the error template of the current service", - "operationId" : "otoroshi.controllers.adminapi.ServicesController.updateServiceTemplate", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The serviceId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" - } - } - } - } - } - }, - "/api/status" : { - "post" : { - "tags" : [ "analytics" ], - "summary" : "Status for some/all services over time", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.servicesStatus", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ServiceDescriptorList" - } - } - } - } - } - }, - "/api/privateapps/sessions/send/{id}/{username}" : { - "post" : { - "tags" : [ "privateapps" ], - "summary" : "Send an email to a user to update its own settings", - "operationId" : "otoroshi.controllers.PrivateAppsController.sendSelfUpdateLink", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - }, { - "name" : "username", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the username parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/admins/simple" : { - "post" : { - "tags" : [ "admins" ], - "summary" : "Register an admin user", - "operationId" : "otoroshi.controllers.adminapi.UsersController.registerSimpleAdmin", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - } - } - } - }, - "get" : { - "tags" : [ "admins" ], - "summary" : "Returns all admins", - "operationId" : "otoroshi.controllers.adminapi.UsersController.simpleAdmins", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SimpleAdminList" - } - } - } - } - } - } - }, - "/api/auths/{id}/register/start" : { - "post" : { - "tags" : [ "auth-modules" ], - "summary" : "Stats the registration of a user", - "operationId" : "otoroshi.controllers.adminapi.AuthModulesController.startRegistration", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/WebAuthnRegistrationStartBody" - } - } - } - } - } - }, - "/api/services/{serviceId}/status" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Status of a service over time", - "operationId" : "otoroshi.controllers.adminapi.AnalyticsController.serviceStatus", - "parameters" : [ { - "name" : "serviceId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the serviceId parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/experimental/services/_openapi" : { - "post" : { - "tags" : [ "experimental" ], - "summary" : "Generates a service based on an openapi spec.", - "operationId" : "otoroshi.next.controllers.adminapi.NgServicesController.fromOpenapi", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/ServiceFromOpenApiBody" - } - } - } - } - } - }, - "/api/experimental/targets/_bulk" : { - "patch" : { - "tags" : [ "experimental" ], - "summary" : "Update (using json-patch) multiple StoredNgTargets at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.bulkPatchAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkPatchBody" - } - } - } - } - }, - "post" : { - "tags" : [ "experimental" ], - "summary" : "Create multiple StoredNgTargets at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.bulkCreateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "experimental" ], - "summary" : "Delete multiple StoredNgTargets at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.bulkDeleteAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - } - }, - "put" : { - "tags" : [ "experimental" ], - "summary" : "Update multiple StoredNgTargets at the same time", - "operationId" : "otoroshi.next.controllers.adminapi.NgTargetsController.bulkUpdateAction", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/BulkResponseBody" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - } - } - } - } - } - } - }, - "/api/scripts/_compile" : { - "post" : { - "tags" : [ "scripts" ], - "summary" : "Trigger script compilation of the server", - "operationId" : "otoroshi.controllers.adminapi.ScriptApiController.compileScript", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Any" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/CodeBody" - } - } - } - } - } - }, - "/api/experimental/certificates/_by_domain" : { - "get" : { - "tags" : [ "experimental" ], - "summary" : "Experimental payload", - "operationId" : "otoroshi.next.controllers.adminapi.NgRoutesController.domainsAndCertificates", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Unknown" - } - } - } - } - } - } - }, - "/api/pki/cas/{ca}/certs/_sign" : { - "post" : { - "tags" : [ "pki" ], - "summary" : "Sign a certificate based on a CSR", - "operationId" : "otoroshi.controllers.adminapi.PkiController.signCert", - "parameters" : [ { - "name" : "ca", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the ca parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.SignCertResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/PemCsrBody" - } - } - } - } - } - }, - "/api/cluster/login-tokens/{id}" : { - "post" : { - "tags" : [ "cluster" ], - "summary" : "Api to create a distributed login token between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.createLoginToken", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TokenResponse" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - }, - "get" : { - "tags" : [ "cluster" ], - "summary" : "Api to check a distributed login token between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.isLoginTokenValid", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "the id parameter" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TokenResponse" - } - } - } - } - } - } - }, - "/api/certificates/{certId}/_renew" : { - "post" : { - "tags" : [ "certificates" ], - "summary" : "Renew a certificates with the same attributes as the original one", - "operationId" : "otoroshi.controllers.adminapi.CertificatesController.renewCert", - "parameters" : [ { - "name" : "certId", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The certId param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Empty" - } - } - } - } - } - }, - "/api/tcp/services/{id}" : { - "patch" : { - "tags" : [ "tcp" ], - "summary" : "Updates (using json-patch) a specific TcpService using its id", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.patchEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "get" : { - "tags" : [ "tcp" ], - "summary" : "Find a specific TcpService using its id", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.findEntityByIdAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - }, - "delete" : { - "tags" : [ "tcp" ], - "summary" : "Deletes a specific TcpService using its id", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.deleteEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - }, - "put" : { - "tags" : [ "tcp" ], - "summary" : "Updates a specific TcpService using its id", - "operationId" : "otoroshi.controllers.adminapi.TcpServiceApiController.updateEntityAction", - "parameters" : [ { - "name" : "id", - "in" : "path", - "schema" : { - "type" : "string" - }, - "required" : true, - "description" : "The id param of the target entity" - } ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body in nd-json format (1 stringified entity per line)", - "required" : true, - "content" : { - "application/x-ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - } - } - } - } - } - }, - "/api/services/_template" : { - "get" : { - "tags" : [ "services" ], - "summary" : "Creates a new Service from a template", - "operationId" : "otoroshi.controllers.adminapi.TemplatesController.initiateService_services", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - } - } - } - } - } - }, - "/api/cluster/sessions" : { - "post" : { - "tags" : [ "cluster" ], - "summary" : "Api to create a distributed private apps session between worker and leader", - "operationId" : "otoroshi.controllers.adminapi.ClusterController.createSession", - "parameters" : [ ], - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Resource not found or does not exist", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.PrivateAppsUser" - } - } - } - } - }, - "requestBody" : { - "description" : "the request body", - "required" : true, - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/otoroshi.models.PrivateAppsUser" - } - } - } - } - } - } - }, - "components" : { - "schemas" : { - "otoroshi.models.ElasticAnalyticsConfig" : { - "description" : "Settings for connection to an elastic cluster", - "type" : "object", - "properties" : { - "clusterUri" : { - "description" : "Cluster URL", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Additionnal headers in the http request" - }, - "password" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Elastic password" - }, - "indexSettings" : { - "description" : "Indexation settings", - "$ref" : "#/components/schemas/otoroshi.models.IndexSettings" - }, - "mtlsConfig" : { - "description" : "TLS settings for the http client", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "index" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Index name" - }, - "type" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Object type", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "applyTemplate" : { - "description" : "Enable template creation/update", - "type" : "boolean" - }, - "version" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Version of Elasticsearch" - }, - "user" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Elasticsearch user" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesIngressControllerJob" : { - "description" : "Plugin to sync kubernetes ingresses with otoroshi", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgRouteDataStore" : { - "description" : "The datastore for routes", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.CorsSettings" : { - "description" : "Settings for CORS support", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Whether or not cors is enabled", - "type" : "boolean" - }, - "allowCredentials" : { - "description" : "Allow to pass credentials", - "type" : "boolean" - }, - "maxAge" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "number" - } ], - "description" : "Cors max age" - }, - "allowMethods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The cors allowed methods" - }, - "allowHeaders" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The cors allowed headers" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The cors excluded patterns" - }, - "exposeHeaders" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The cors exposed header" - }, - "allowOrigin" : { - "description" : "The cors allowed origin", - "type" : "string" - } - } - }, - "otoroshi.plugins.apikeys.BiscuitConf" : { - "description" : "Configuration for the biscuit plugin", - "type" : "object", - "properties" : { - "privkey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Biscuit private key" - }, - "checks" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit checks" - }, - "facts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit facts" - }, - "rules" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit rules" - } - } - }, - "otoroshi.models.LargeResponseFaultConfig" : { - "description" : "Settings for a large response fault (chaos engineering)", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0", - "type" : "number" - }, - "additionalResponseSize" : { - "format" : "int32", - "description" : "Add n 0 bytes", - "type" : "integer" - } - } - }, - "otoroshi.models.MappingSettings" : { - "description" : "Settings to transform a jwt token", - "type" : "object", - "properties" : { - "map" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Change values" - }, - "values" : { - "description" : "Add values", - "type" : "object" - }, - "remove" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Remove some token claims" - } - } - }, - "otoroshi.next.models.NgContextualPlugins" : { - "description" : "The plugins that will be triggered for the current request", - "type" : "object", - "properties" : { - "_env" : { - "description" : "The current env", - "$ref" : "#/components/schemas/otoroshi.env.Env" - }, - "next_plugins_merge" : { - "description" : "Try to merge synchronous and contiguous plugins", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesEntity" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.ApikeyQuotas" : { - "description" : "Plugin to apply quotas en apikeys", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.core.apikeys.JwtApikeyExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.GzipResponseCompressor" : { - "description" : "Plugin for gzip compression", - "type" : "object", - "properties" : { - "compression_level" : { - "format" : "int32", - "description" : "The compression level (1 to 9)", - "type" : "integer" - }, - "buffer_size" : { - "format" : "int32", - "description" : "Compressor buffer size", - "type" : "integer" - }, - "chunked_threshold" : { - "format" : "int32", - "description" : "Chunk size", - "type" : "integer" - }, - "excluded_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The excluded path patterns" - }, - "white_list" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed mimetypes list" - }, - "black_list" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Blocked mimetypes list" - } - } - }, - "otoroshi.models.VerificationSettings" : { - "description" : "jwt token verification settings", - "type" : "object", - "properties" : { - "fields" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Fields validation" - }, - "arrayFields" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Fields array validation" - } - } - }, - "otoroshi.next.models.NgMinimalRoute" : { - "description" : "A route representation with it's minimal attributes", - "type" : "object", - "properties" : { - "backend_ref" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The backend id of the route (if one)" - }, - "frontend" : { - "description" : "The frontend of the route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgFrontend" - }, - "override_plugins" : { - "description" : "Override global plugin list from route composition", - "type" : "boolean" - }, - "backend" : { - "description" : "The backend of the route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgMinimalBackend" - } - } - }, - "otoroshi.next.plugins.NgLatencyInjectionFaultConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The ratio of requests impacted", - "type" : "number" - }, - "from" : { - "description" : "Lower bound of latency injection", - "type" : "number" - }, - "to" : { - "description" : "Upper bound of latency injection", - "type" : "number" - } - } - }, - "otoroshi.next.plugins.JwtVerification" : { - "description" : "Plugin to verify jwt token", - "type" : "object", - "properties" : { - "verifiers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of verifiers id" - } - } - }, - "otoroshi.plugins.log4j.Log4jExpressionText" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "value" : { - "description" : "A parsed text for log4jshell evaluation", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.NgGzipConfig" : { - "description" : "Configuration for Gzip", - "type" : "object", - "properties" : { - "compression_level" : { - "format" : "int32", - "description" : "The compression level (1 to 9)", - "type" : "integer" - }, - "buffer_size" : { - "format" : "int32", - "description" : "Compressor buffer size", - "type" : "integer" - }, - "chunked_threshold" : { - "format" : "int32", - "description" : "Chunk size", - "type" : "integer" - }, - "excluded_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The excluded path patterns" - }, - "white_list" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed mimetypes list" - }, - "black_list" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Blocked mimetypes list" - } - } - }, - "otoroshi.next.plugins.W3CTracingConfigKind" : { - "description" : "Configuration for W3CTracing", - "type" : "string", - "enum" : [ "jaeger", "zipkin", "logger", "noop" ] - }, - "otoroshi.next.plugins.JQConfig" : { - "description" : "Configuration for JQ", - "type" : "object", - "properties" : { - "request" : { - "description" : "JQ filter for request", - "type" : "string" - }, - "response" : { - "description" : "JQ filter for response", - "type" : "string" - } - } - }, - "otoroshi.models.TeamId" : { - "type" : "string", - "description" : "team id" - }, - "otoroshi.next.plugins.NgAllowedMethodsConfig" : { - "description" : "Configuration for AllowHttpMethods", - "type" : "object", - "properties" : { - "allowed" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of allowed methods" - }, - "forbidden" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of forbidden methods" - } - } - }, - "WebauthnAdminList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } - }, - "otoroshi.models.RegionMatch" : { - "description" : "Match a target if in the same region", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - }, - "region" : { - "description" : "Region name", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.Cors" : { - "description" : "Plugin to use cors", - "type" : "object", - "properties" : { - "allow_credentials" : { - "description" : "Allowed credentials", - "type" : "boolean" - }, - "max_age" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "number" - } ], - "description" : "cors max age" - }, - "allow_origin" : { - "description" : "Allowed cors origins", - "type" : "string" - }, - "allow_methods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed cors methods" - }, - "excluded_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths without cors" - }, - "allow_headers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed cors headers" - }, - "expose_headers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Exposed cors headers" - } - } - }, - "ErrorTemplateList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" - } - }, - "otoroshi.next.plugins.PublicPrivatePaths" : { - "description" : "Plugin to define public and private paths", - "type" : "object", - "properties" : { - "strict" : { - "description" : "apikey only", - "type" : "boolean" - }, - "public_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths that should not have user or apikey to pass" - }, - "private_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths that should have user or apikey to pass" - } - } - }, - "otoroshi.auth.GroupRights" : { - "description" : "User rights associated with a group", - "type" : "object", - "properties" : { - "userRights" : { - "description" : "The user rights associated with this group", - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "users" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The users associated with this group" - } - } - }, - "otoroshi.plugins.quotas.ServiceQuotasConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "throttlingQuota" : { - "format" : "int64", - "description" : "Calls quota per second", - "type" : "integer" - }, - "dailyQuota" : { - "format" : "int64", - "description" : "Daily calls quota", - "type" : "integer" - }, - "monthlyQuota" : { - "format" : "int64", - "description" : "Monthly calls quota", - "type" : "integer" - } - } - }, - "otoroshi.next.plugins.ApikeyCalls" : { - "description" : "Plugin to use apikeys", - "type" : "object", - "properties" : { - "extractors" : { - "description" : "Configuration of the apikey extraction modes", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractors" - }, - "pass_with_user" : { - "description" : "Let the request pass if a user is connected", - "type" : "boolean" - }, - "wipe_backend_request" : { - "description" : "Removes the apikeys from the request to not forward it to the backend", - "type" : "boolean" - }, - "validate" : { - "description" : "Enabled quotas validation", - "type" : "boolean" - }, - "routing" : { - "description" : "Use apikey for routing", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyMatcher" - }, - "update_quotas" : { - "description" : "???", - "type" : "boolean" - } - } - }, - "otoroshi.script.AccessContext" : { - "description" : "Context for AccessValidation plugins", - "type" : "object", - "properties" : { - "attrs" : { - "description" : "The current request attributes", - "$ref" : "#/components/schemas/otoroshi.utils.TypedMap" - }, - "config" : { - "description" : "The current plugin config.", - "type" : "object" - }, - "descriptor" : { - "description" : "The current service descriptor", - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - }, - "index" : { - "format" : "int32", - "description" : "The current plugin index", - "type" : "integer" - }, - "globalConfig" : { - "description" : "The current global config", - "type" : "object" - }, - "apikey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } ], - "description" : "The current apikey" - }, - "snowflake" : { - "description" : "The current request snowflake", - "type" : "string" - }, - "user" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.PrivateAppsUser" - } ], - "description" : "The current user" - } - } - }, - "otoroshi.next.plugins.JQResponseConfig" : { - "description" : "Configuration for JQResponse", - "type" : "object", - "properties" : { - "filter" : { - "description" : "JQ filter for response", - "type" : "string" - } - } - }, - "otoroshi.utils.http.MtlsConfig" : { - "description" : "TLS settings for the http client", - "type" : "object", - "properties" : { - "mtls" : { - "description" : "Enabled", - "type" : "boolean" - }, - "loose" : { - "description" : "Loose verification", - "type" : "boolean" - }, - "trustAll" : { - "description" : "Trust any certificate", - "type" : "boolean" - }, - "trustedCerts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Trusted cert. ids" - }, - "certs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Trusted cert. ids" - } - } - }, - "otoroshi.plugins.geoloc.IpStackGeolocationInfoExtractor" : { - "description" : "Plugin that extracts geolocation based on ipstack", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.metrics.PrometheusServiceMetrics" : { - "description" : "Plugin to collect service metrics", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesClient" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "config" : { - "description" : "The current client config.", - "$ref" : "#/components/schemas/otoroshi.plugins.jobs.kubernetes.KubernetesConfig" - }, - "env" : { - "description" : "The current env", - "$ref" : "#/components/schemas/otoroshi.env.Env" - } - } - }, - "otoroshi.models.RefJwtVerifier" : { - "description" : "Reference to a jwt verifier", - "type" : "object", - "properties" : { - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Verifier excluded paths" - }, - "ids" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Verifiers ids" - }, - "type" : { - "description" : "the kind of verifier", - "type" : "string", - "enum" : [ "global", "local", "ref" ] - }, - "enabled" : { - "description" : "Verifier enabled", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.ViolationsException" : { - "description" : "???", - "type" : "object", - "properties" : { - "errors" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "???" - } - } - }, - "TokenResponse" : { - "type" : "object", - "description" : "User login token response", - "properties" : { - "valid" : { - "type" : "string" - } - } - }, - "otoroshi.next.plugins.AuthModule" : { - "description" : "Plugin to use auth. modules", - "type" : "object", - "properties" : { - "module" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Id of the auth. module" - }, - "pass_with_apikey" : { - "description" : "let the request pass if an apikey is present", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.clientcert.HasClientCertValidator" : { - "description" : "Plugin that validates client certificates", - "type" : "object", - "properties" : { } - }, - "ScriptsList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - } - }, - "otoroshi.models.WeightedBestResponseTime" : { - "description" : "Loadbalancing policy that route to best response time targets with a weight", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "Weight ratio", - "type" : "number" - } - } - }, - "otoroshi.next.plugins.AdditionalHeadersIn" : { - "description" : "Plugin that add headers on a request", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The headers added to the request" - } - } - }, - "LetsEncryptCertBody" : { - "type" : "object", - "description" : "PEM encoded certificate" - }, - "otoroshi.controllers.ServiceLike" : { - "description" : "???", - "type" : "object", - "properties" : { - "entity" : { - "description" : "???", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocationSupport" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "???" - } - } - }, - "otoroshi.script.PreRoutingContext" : { - "description" : "Context for preroutes plugins", - "type" : "object", - "properties" : { - "globalConfig" : { - "description" : "The current global config", - "type" : "object" - }, - "snowflake" : { - "description" : "The current request snowflake", - "type" : "string" - }, - "descriptor" : { - "description" : "The current service descriptor", - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - }, - "config" : { - "description" : "The current plugin config.", - "type" : "object" - }, - "index" : { - "format" : "int32", - "description" : "The current plugin index", - "type" : "integer" - }, - "attrs" : { - "description" : "The current request attributes", - "$ref" : "#/components/schemas/otoroshi.utils.TypedMap" - } - } - }, - "otoroshi.next.plugins.IpAddressAllowedList" : { - "description" : "Plugin to allow only some ip addresses", - "type" : "object", - "properties" : { - "addresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of allowed ip addresses of cidr blocks" - } - } - }, - "otoroshi.plugins.apikeys.ApikeyAuthModule" : { - "description" : "Plugin that authenticate a website based on apikeys", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.CustomTimeouts" : { - "description" : "Settings for custom timeouts for a specific path", - "type" : "object", - "properties" : { - "path" : { - "description" : "path on which this configuration works", - "type" : "string" - }, - "callAndStreamTimeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (hard timeout, connection will be closed after that duration)", - "type" : "integer" - }, - "callTimeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (soft timeout as it's enforced by the circuit breaker)", - "type" : "integer" - }, - "idleTimeout" : { - "format" : "int64", - "description" : "Timeout on idle connection", - "type" : "integer" - }, - "globalTimeout" : { - "format" : "int64", - "description" : "Specify how long the global call (with retries) should last at most in milliseconds", - "type" : "integer" - }, - "connectionTimeout" : { - "format" : "int64", - "description" : "Timeout at connection", - "type" : "integer" - } - } - }, - "otoroshi.models.BasicAuthConstraints" : { - "description" : "Settings to extract apikey from a basic auth header like", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Constraint enabled", - "type" : "boolean" - }, - "headerName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to get client_id:client_secret base64 encoded" - }, - "queryName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Query param name to get client_id:client_secret base64 encoded" - } - } - }, - "otoroshi.models.Transform" : { - "description" : "jwt token transformation policy settings", - "type" : "object", - "properties" : { - "transformSettings" : { - "description" : "Transformation settings", - "$ref" : "#/components/schemas/otoroshi.models.TransformSettings" - }, - "algoSettings" : { - "description" : "Algorithm settings for re-signing token", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "verificationSettings" : { - "description" : "Verification settings", - "$ref" : "#/components/schemas/otoroshi.models.VerificationSettings" - }, - "type" : { - "description" : "the kind of strategy", - "type" : "string", - "enum" : [ "PassThrough", "Sign", "Transform", "DefaultToken" ] - } - } - }, - "otoroshi.models.KidAlgoSettings" : { - "description" : "Settings to find keypair based on header kid for verification", - "type" : "object", - "properties" : { - "onlyExposedCerts" : { - "description" : "Use only exposed certs", - "type" : "boolean" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.next.plugins.GraphQLProxyConfig" : { - "description" : "???", - "type" : "object", - "properties" : { - "max_complexity" : { - "format" : "double", - "description" : "???", - "type" : "number" - }, - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "path" : { - "description" : "???", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "???" - }, - "endpoint" : { - "description" : "???", - "type" : "string" - }, - "max_depth" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - } - } - }, - "otoroshi.plugins.loggers.ResponseBodyEvent" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "The response status", - "type" : "integer" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The response headers" - }, - "url" : { - "description" : "The request url", - "type" : "string" - }, - "reqId" : { - "description" : "The request id", - "type" : "string" - }, - "from" : { - "description" : "The incoming request ip address", - "type" : "string" - }, - "ua" : { - "description" : "The user agent", - "type" : "string" - }, - "method" : { - "description" : "The request method", - "type" : "string" - } - } - }, - "otoroshi.models.AlwaysMatch" : { - "type" : "object", - "description" : "Always select target", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "Always" ] - } - } - }, - "otoroshi.next.plugins.MockResponses" : { - "description" : "Plugin to mock responses", - "type" : "object", - "properties" : { - "responses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockResponse" - }, - "description" : "Possible responses" - }, - "pass_through" : { - "description" : "Pass the call if no mocked response found", - "type" : "boolean" - }, - "form_data" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockFormData" - } ], - "description" : "???" - } - } - }, - "otoroshi.models.TenantId" : { - "type" : "string", - "description" : "organization id" - }, - "otoroshi.auth.SAMLCanocalizationMethod" : { - "description" : "Canonicalization Method for XML Signatures", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgTreeRouter_Test" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "Done" : { - "type" : "object", - "description" : "operation is done", - "properties" : { - "done" : { - "type" : "boolean" - } - } - }, - "UserTokenBody" : { - "type" : "object", - "properties" : { - "token" : { - "type" : "string" - } - } - }, - "otoroshi.utils.mailer.MailgunSettings" : { - "description" : "Settings for the mailgun mailer", - "type" : "object", - "properties" : { - "eu" : { - "description" : "European tenant", - "type" : "boolean" - }, - "apiKey" : { - "description" : "Mailgun apikey", - "type" : "string" - }, - "domain" : { - "description" : "Mailgun domain", - "type" : "string" - }, - "to" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.EmailLocation" - }, - "description" : "Destination email address" - }, - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - } - } - }, - "otoroshi.models.FileSettings" : { - "description" : "Settings to export to a file", - "type" : "object", - "properties" : { - "path" : { - "description" : "File path", - "type" : "string" - }, - "maxFileSize" : { - "format" : "int64", - "description" : "Max file size for rolling", - "type" : "integer" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - } - } - }, - "otoroshi.plugins.workflow.WorkflowEndpoint" : { - "description" : "Experimental plugin", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.InfraProviderMatch" : { - "description" : "Match a target if in the same infrastructure", - "type" : "object", - "properties" : { - "provider" : { - "description" : "provider name", - "type" : "string" - }, - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - } - } - }, - "otoroshi.models.Exporter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.events.KafkaConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.events.PulsarConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ConsoleSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ElasticAnalyticsConfig" - }, { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ExporterRef" - }, { - "$ref" : "#/components/schemas/otoroshi.models.FileSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.MetricsSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.Webhook" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.ConsoleMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.GenericMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailgunSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailjetSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.NoneMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.SendgridSettings" - } ] - }, - "otoroshi.plugins.discovery.SelfRegistrationConfig" : { - "description" : "Configuration for the DiscoverySelfRegistrationTransformer plugin", - "type" : "object", - "properties" : { - "registrationTtl" : { - "description" : "the ttl for a service registration", - "type" : "number" - }, - "targetTemplate" : { - "description" : "A json template for otoroshi target", - "type" : "object" - }, - "hosts" : { - "description" : "The possible list of hosts for a service", - "type" : "array", - "items" : { - "type" : "string" - } - } - } - }, - "otoroshi.next.models.NgMatchedRoutes" : { - "description" : "A set of matched routes in the new router", - "type" : "object", - "properties" : { - "routes" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - }, - "description" : "Current matched route" - }, - "path" : { - "description" : "Current matched path", - "type" : "string" - }, - "no_more_segments" : { - "description" : "Is the path fully matched", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.JsonToXmlResponse" : { - "description" : "Plugin to transform json body to xml", - "type" : "object", - "properties" : { - "filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform json entity" - } - } - }, - "otoroshi.auth.LdapAuthModuleConfig" : { - "description" : "Authentication module that works with LDAP", - "type" : "object", - "properties" : { - "groupFilters" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.GroupFilter" - }, - "description" : "LDAP group filters" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata of the module" - }, - "allowEmptyPassword" : { - "description" : "Allow empty password access", - "type" : "boolean" - }, - "basicAuth" : { - "description" : "Use standard basic auth or web login form", - "type" : "boolean" - }, - "searchBase" : { - "description" : "LDAP search base", - "type" : "string" - }, - "nameField" : { - "description" : "Field name to get name from user profile", - "type" : "string" - }, - "emailField" : { - "description" : "Field name to get email from user profile", - "type" : "string" - }, - "extractProfileFilterNot" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Exclude LDAP properties matching" - }, - "type" : { - "description" : "the type of the module", - "type" : "string", - "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] - }, - "metadataField" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Field name to get metadata from user profile" - }, - "rightsOverride" : { - "type" : "object", - "additionalProperties" : { - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "description" : "Overrides user rights. Object with email as key" - }, - "clientSideSessionEnabled" : { - "description" : "???", - "type" : "boolean" - }, - "groupRights" : { - "type" : "object", - "additionalProperties" : { - "$ref" : "#/components/schemas/otoroshi.auth.GroupRights" - }, - "description" : "Rights associated with groups" - }, - "id" : { - "description" : "Unique id of the config", - "type" : "string" - }, - "extraMetadata" : { - "description" : "Add metadata to user. Object with email as key", - "type" : "object" - }, - "searchFilter" : { - "description" : "Filter for users", - "type" : "string" - }, - "adminPassword" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The admin password" - }, - "extractProfileFilter" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Only include LDAP properties matching" - }, - "sessionCookieValues" : { - "description" : "Settings for the session cookie", - "$ref" : "#/components/schemas/otoroshi.auth.SessionCookieValues" - }, - "dataOverride" : { - "type" : "object", - "additionalProperties" : { - "type" : "object" - }, - "description" : "Overiddes user data. Object with email as key" - }, - "superAdmins" : { - "description" : "This module produces only super admins", - "type" : "boolean" - }, - "userBase" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "LDAP user base DN" - }, - "serverUrls" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "LDAP server list of url" - }, - "userValidators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "Validators that will check if the current user is authorized after successful login" - }, - "_loc" : { - "description" : "Location of the module", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "sessionMaxAge" : { - "format" : "int32", - "description" : "Max age of the session", - "type" : "integer" - }, - "adminUsername" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The admin username" - }, - "extractProfile" : { - "description" : "Extract profile from LDAP profile", - "type" : "boolean" - }, - "name" : { - "description" : "Name of the config", - "type" : "string" - }, - "desc" : { - "description" : "Description of the config", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.Keys" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.QuotasAlmostExceededSettings" : { - "description" : "Settings for apikey quotas alerts", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Is quotas alert enabled", - "type" : "boolean" - }, - "dailyQuotasThreshold" : { - "format" : "double", - "description" : "The daily quotas threshold before generating alert", - "type" : "number" - }, - "monthlyQuotasThreshold" : { - "format" : "double", - "description" : "The monthly quotas threshold before generating alert", - "type" : "number" - } - } - }, - "otoroshi.next.plugins.JQResponse" : { - "description" : "Plugin to transform body with JQ filters", - "type" : "object", - "properties" : { - "filter" : { - "description" : "JQ filter for response", - "type" : "string" - } - } - }, - "otoroshi.models.Team" : { - "description" : "An otoroshi model for a team of users in the organization (otoroshi-ui)", - "type" : "object", - "properties" : { - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "tenant" : { - "description" : "Entity organization", - "$ref" : "#/components/schemas/otoroshi.models.TenantId" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "id" : { - "description" : "Entity id", - "$ref" : "#/components/schemas/otoroshi.models.TeamId" - } - } - }, - "otoroshi.models.ChaosConfig" : { - "description" : "Settings to enable chaos engineering for a service", - "type" : "object", - "properties" : { - "badResponsesFaultConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.BadResponsesFaultConfig" - } ], - "description" : "Settings for bad responses" - }, - "largeRequestFaultConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.LargeRequestFaultConfig" - } ], - "description" : "Settings for large requests" - }, - "largeResponseFaultConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.LargeResponseFaultConfig" - } ], - "description" : "Settings for large responses" - }, - "latencyInjectionFaultConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.LatencyInjectionFaultConfig" - } ], - "description" : "Settings for latency injection" - }, - "enabled" : { - "description" : "Whether or not this config is enabled", - "type" : "boolean" - } - } - }, - "otoroshi.events.HealthCheckEvent" : { - "description" : "Events generated by health checks", - "type" : "object", - "properties" : { - "error" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Error if any" - }, - "health" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Health status" - }, - "logicCheck" : { - "description" : "Did the service respond with the logic check", - "type" : "boolean" - }, - "status" : { - "format" : "int32", - "description" : "Check status", - "type" : "integer" - }, - "url" : { - "description" : "Checked url", - "type" : "string" - }, - "duration" : { - "format" : "int64", - "description" : "Duration of the call", - "type" : "integer" - } - } - }, - "otoroshi.plugins.authcallers.OAuth2Kind" : { - "description" : "The kind of oauth2 flow", - "type" : "string", - "enum" : [ "client_credentials", "password" ] - }, - "otoroshi.models.SecComVersion" : { - "type" : "string", - "enum" : [ "V1", "v2" ], - "description" : "Version of the challenge token" - }, - "otoroshi.plugins.authcallers.OAuth2Caller" : { - "description" : "Plugin that can call an oauth2 client_credentials flow or password flow backend", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.TransformSettings" : { - "description" : "jwt token transformation settings", - "type" : "object", - "properties" : { - "location" : { - "description" : "Location of the token", - "$ref" : "#/components/schemas/otoroshi.models.JwtTokenLocation" - }, - "mappingSettings" : { - "description" : "Token mapping settings", - "$ref" : "#/components/schemas/otoroshi.models.MappingSettings" - } - } - }, - "ServiceDescriptorList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - } - }, - "otoroshi.plugins.izanami.IzanamiCanaryRoutingConfigRoute" : { - "description" : "Configuration for IzanamiCanary", - "type" : "object", - "properties" : { - "variants" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The possible variant" - }, - "wildcard" : { - "description" : "Wildcard match", - "type" : "boolean" - }, - "default" : { - "description" : "The default variant", - "type" : "string" - }, - "regex" : { - "description" : "Regex match", - "type" : "boolean" - }, - "exact" : { - "description" : "Exact match", - "type" : "boolean" - }, - "route" : { - "description" : "The route path", - "type" : "string" - } - } - }, - "otoroshi.models.ApiKey" : { - "description" : "An otoroshi apikey that can allow you to access some services", - "type" : "object", - "properties" : { - "dailyQuota" : { - "format" : "int64", - "description" : "Authorized number of calls per day", - "type" : "integer" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Bunch of metadata for the key" - }, - "throttlingQuota" : { - "format" : "int64", - "description" : "Authorized number of calls per second, measured on 10 seconds", - "type" : "integer" - }, - "constrainedServicesOnly" : { - "description" : "This apikey can only be used on services that constrained their apikey routing", - "type" : "boolean" - }, - "allowClientIdOnly" : { - "description" : "This apikey can be used juste with the client_id value", - "type" : "boolean" - }, - "_loc" : { - "description" : "The location of the apikey", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "restrictions" : { - "description" : "Apikey restrictions settings", - "$ref" : "#/components/schemas/otoroshi.models.Restrictions" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Apikey tags" - }, - "enabled" : { - "description" : "Whether or not the key is enabled. If disabled, resources won't be available to calls using this key", - "type" : "boolean" - }, - "readOnly" : { - "description" : "The apikey only allow access for GET, HEAD and OPTIONS verbs", - "type" : "boolean" - }, - "clientSecret" : { - "description" : "The secret of the Api Key. Usually 64 random alpha numerical characters, but can be anything", - "type" : "string" - }, - "validUntil" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "number" - } ], - "description" : "Date until when the apikey is valid" - }, - "clientName" : { - "description" : "The name of the api key, for humans ;-)", - "type" : "string" - }, - "monthlyQuota" : { - "format" : "int64", - "description" : "Authorized number of calls per month", - "type" : "integer" - }, - "description" : { - "description" : "Description of this apikey", - "type" : "string" - }, - "rotation" : { - "description" : "Apikey rotation settings", - "$ref" : "#/components/schemas/otoroshi.models.ApiKeyRotation" - }, - "authorizedEntities" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.EntityIdentifier" - }, - "description" : "The group/service ids (prefixed by group_ or service_ on which the key is authorized" - }, - "clientId" : { - "description" : "The unique id of the Api Key. Usually 16 random alpha numerical characters, but can be anything", - "type" : "string" - } - } - }, - "otoroshi.plugins.oidc.OIDCAccessTokenValidator" : { - "description" : "Plugin to validate OIDC token ", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.UserRight" : { - "description" : "Represent a user right (teams, organizations) in otoroshi-ui", - "type" : "object", - "properties" : { - "tenant" : { - "description" : "Access rights on organizations", - "$ref" : "#/components/schemas/otoroshi.models.TenantAccess" - }, - "teams" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.TeamAccess" - }, - "description" : "Access rights on teams" - } - } - }, - "otoroshi.models.InHeader" : { - "description" : "JWT token location (header)", - "type" : "object", - "properties" : { - "name" : { - "description" : "Header name", - "type" : "string" - }, - "type" : { - "description" : "the kind of location", - "type" : "string", - "enum" : [ "InQueryParam", "InHeader", "InCookie" ] - }, - "remove" : { - "description" : "Remove from value", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.MockResource" : { - "description" : "???", - "type" : "object", - "properties" : { - "name" : { - "description" : "???", - "type" : "string" - }, - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockField" - }, - "description" : "???" - }, - "additional_data" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "???" - } - } - }, - "otoroshi.auth.GenericOauth2ModuleConfig" : { - "description" : "Authentication module that works with OAuth2/OIDC", - "type" : "object", - "properties" : { - "refreshTokens" : { - "description" : "Refresh token support", - "type" : "boolean" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata of the module" - }, - "tokenUrl" : { - "description" : "OAuth token URL", - "type" : "string" - }, - "otoroshiRightsField" : { - "description" : "Field in user profile to find otoroshi UI rights", - "type" : "string" - }, - "mtlsConfig" : { - "description" : "TLS config. for the module (for server accessed endpoints like tokenUrl, introspectionUrl, etc)", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "nameField" : { - "description" : "Field name to get name from user profile", - "type" : "string" - }, - "emailField" : { - "description" : "Field name to get email from user profile", - "type" : "string" - }, - "type" : { - "description" : "the type of the module", - "type" : "string", - "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] - }, - "introspectionUrl" : { - "description" : "URL to introspect access_token", - "type" : "string" - }, - "loginUrl" : { - "description" : "OAuth login URL", - "type" : "string" - }, - "scope" : { - "description" : "The scope of the token", - "type" : "string" - }, - "rightsOverride" : { - "type" : "object", - "additionalProperties" : { - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "description" : "Overrides user rights. Object with email as key" - }, - "clientSideSessionEnabled" : { - "description" : "???", - "type" : "boolean" - }, - "callbackUrl" : { - "description" : "Otoroshi callback URL", - "type" : "string" - }, - "clientSecret" : { - "description" : "OAuth Client secret", - "type" : "string" - }, - "id" : { - "description" : "Unique id of the config", - "type" : "string" - }, - "extraMetadata" : { - "description" : "Add metadata to user. Object with email as key", - "type" : "object" - }, - "accessTokenField" : { - "description" : "Field name to get access token", - "type" : "string" - }, - "userInfoUrl" : { - "description" : "OAuth userinfo to get user profile", - "type" : "string" - }, - "clientId" : { - "description" : "OAuth Client id", - "type" : "string" - }, - "useCookie" : { - "description" : "Use cookies for redirection", - "type" : "boolean" - }, - "authorizeUrl" : { - "description" : "OAuth authorize URL", - "type" : "string" - }, - "sessionCookieValues" : { - "description" : "Settings for the session cookie", - "$ref" : "#/components/schemas/otoroshi.auth.SessionCookieValues" - }, - "dataOverride" : { - "type" : "object", - "additionalProperties" : { - "type" : "object" - }, - "description" : "Overiddes user data. Object with email as key" - }, - "superAdmins" : { - "description" : "This module produces only super admins", - "type" : "boolean" - }, - "apiKeyMetaField" : { - "description" : "Field name to extract apikey metadata", - "type" : "string" - }, - "useJson" : { - "description" : "Use JSON or URL Form Encoded as payload with the OAuth provider", - "type" : "boolean" - }, - "pkce" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.PKCEConfig" - } ], - "description" : "Use PKCE challenge (OAuth 2.1)" - }, - "apiKeyTagsField" : { - "description" : "Field name to extract apikey tags", - "type" : "string" - }, - "otoroshiDataField" : { - "description" : "Field name to get otoroshi metadata from. You can specify sub fields using | as separator", - "type" : "string" - }, - "userValidators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "Validators that will check if the current user is authorized after successful login" - }, - "_loc" : { - "description" : "Location of the module", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "jwtVerifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - } ], - "description" : "Algo. settings to verify JWT token" - }, - "sessionMaxAge" : { - "format" : "int32", - "description" : "max age for the session cookie in seconds", - "type" : "integer" - }, - "proxy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy configuration for the module's http client" - }, - "logoutUrl" : { - "description" : "OAuth logout URL", - "type" : "string" - }, - "oidConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "URL of the OIDC config. file" - }, - "noWildcardRedirectURI" : { - "description" : "Manage redirection without query params for exact string comparison (OAuth 2.1)", - "type" : "boolean" - }, - "readProfileFromToken" : { - "description" : "The user profile will be read from the JWT token in id_token", - "type" : "boolean" - }, - "name" : { - "description" : "Name of the config", - "type" : "string" - }, - "claims" : { - "description" : "The claims of the token", - "type" : "string" - }, - "desc" : { - "description" : "Description of the config", - "type" : "string" - } - } - }, - "otoroshi.plugins.quotas.InstanceQuotas" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "ServiceFromOpenApiBody" : { - "type" : "object", - "description" : "Properties to create a service from an openapi spec", - "properties" : { - "domain" : { - "type" : "string", - "description" : "the domain on which the service will be exposed by otoroshi" - }, - "openapi" : { - "type" : "string", - "description" : "the url to an openapi 3 spec or the content of an openapi 3 spec" - } - } - }, - "otoroshi.next.plugins.JQRequest" : { - "description" : "Plugin to transform body with JQ filters", - "type" : "object", - "properties" : { - "filter" : { - "description" : "JQ filter for request", - "type" : "string" - } - } - }, - "otoroshi.models.GlobalJwtVerifier" : { - "description" : "Otoroshi model for JWT token verifier", - "type" : "object", - "properties" : { - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "algoSettings" : { - "description" : "Algo settings of the verifier", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "name" : { - "description" : "Verifier name", - "type" : "string" - }, - "source" : { - "description" : "Where to find the jwt token", - "$ref" : "#/components/schemas/otoroshi.models.JwtTokenLocation" - }, - "id" : { - "description" : "Verifier id", - "type" : "string" - }, - "type" : { - "description" : "the kind of verifier", - "type" : "string", - "enum" : [ "global" ] - }, - "strict" : { - "description" : "Does it fail if JWT not found", - "type" : "boolean" - }, - "strategy" : { - "description" : "The strategy of the verifier", - "$ref" : "#/components/schemas/otoroshi.models.VerifierStrategy" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "desc" : { - "description" : "Verifier description", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - } - } - }, - "otoroshi.models.ConsoleSettings" : { - "description" : "Settings to export to console", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - } - } - }, - "otoroshi.models.TenantAccess" : { - "description" : "Access rights for organizations", - "type" : "object", - "properties" : { - "canWrite" : { - "description" : "Can this access right write data", - "type" : "boolean" - }, - "value" : { - "description" : "Access pattern", - "type" : "string" - }, - "canRead" : { - "description" : "Can this access right read data", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.discovery.DiscoverySelfRegistrationTransformer" : { - "description" : "Plugin that add services discovery to otoroshi", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.TargetPredicate" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.AlwaysMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.DataCenterMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.GeolocationMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.InfraProviderMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.NetworkLocationMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.RackMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.RegionMatch" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ZoneMatch" - } ] - }, - "otoroshi.models.IpStackGeolocationSettings" : { - "description" : "Settings for connection to IpStack", - "type" : "object", - "properties" : { - "apikey" : { - "description" : "IpStack apikey", - "type" : "string" - }, - "type" : { - "description" : "the kind of geolocation", - "type" : "string", - "enum" : [ "none", "maxmind", "ipstack" ] - }, - "enabled" : { - "description" : "enable ipstack geolocation", - "type" : "boolean" - }, - "timeout" : { - "format" : "int64", - "description" : "API call timeout", - "type" : "integer" - } - } - }, - "otoroshi.models.DefaultTemplates" : { - "description" : "The template that will be merged with newly created entities", - "type" : "object", - "properties" : { - "team" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the team entities" - }, - "script" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the script entities" - }, - "apikey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the apikey entities" - }, - "group" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the group entities" - }, - "tcpService" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the tcpService entities" - }, - "verifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the verifier entities" - }, - "service" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the service entities" - }, - "target" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the target entities" - }, - "certificate" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the certificate entities" - }, - "dataExporter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the dataExporter entities" - }, - "route" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the route entities" - }, - "backend" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the backend entities" - }, - "template" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the template entities" - }, - "tenant" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the tenant entities" - }, - "authConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the authConfig entities" - }, - "descriptor" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "the template for the descriptor entities" - } - } - }, - "otoroshi.auth.SAMLSignature" : { - "description" : "Algorithm and canocalization method used to sign SAML documents", - "type" : "object", - "properties" : { - "algorithm" : { - "description" : "Algorithm to sign documents or assertions", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLSignatureAlgorithm" - }, - "canocalizationMethod" : { - "description" : "Canonicalization Method for XML Signatures", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLCanocalizationMethod" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "UpdateQuotasBody" : { - "type" : "string", - "description" : "" - }, - "otoroshi.next.plugins.MissingHeadersIn" : { - "description" : "Plugin to add headers to a request", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers added to the request if missing" - } - } - }, - "otoroshi.plugins.clientcert.HasClientCertMatchingHttpValidator" : { - "description" : "Plugin that validates client certificates", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.S3ExporterSettings" : { - "description" : "Settings to export to a S3 bucket", - "type" : "object", - "properties" : { - "maxFileSize" : { - "format" : "int64", - "description" : "Max file size for rolling", - "type" : "integer" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "config" : { - "description" : "Exporter settings", - "$ref" : "#/components/schemas/otoroshi.storage.drivers.inmemory.S3Configuration" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.ClientSupport" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "client" : { - "description" : "The actual kubernetes client", - "$ref" : "#/components/schemas/otoroshi.plugins.jobs.kubernetes.KubernetesClient" - }, - "env" : { - "description" : "The current env", - "$ref" : "#/components/schemas/otoroshi.env.Env" - } - } - }, - "otoroshi.plugins.core.DefaultPlugins" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.DataExporterConfigFiltering" : { - "description" : "Filter events to export", - "type" : "object", - "properties" : { - "include" : { - "type" : "array", - "items" : { - "type" : "object" - }, - "description" : "Event include filter" - }, - "exclude" : { - "type" : "array", - "items" : { - "type" : "object" - }, - "description" : "Event exclude filter" - } - } - }, - "PluginDescription" : { - "type" : "object", - "description" : "Description of a plugin", - "properties" : { - "id" : { - "type" : "string", - "description" : "the id of the plugin" - }, - "name" : { - "type" : "string", - "description" : "the name of the plugin" - }, - "description" : { - "type" : "string", - "description" : "the description of the plugin" - }, - "default_config" : { - "type" : "string", - "description" : "the default config of the plugin (for UI form)" - }, - "config_schema" : { - "type" : "string", - "description" : "the config schema of the plugin (for UI form)" - }, - "config_flow" : { - "type" : "array", - "description" : "the config flow of the plugin (for UI form)", - "items" : { - "type" : "string" - } - }, - "plugin_visibility" : { - "type" : "string", - "description" : "visibility of the plugin (can be internal or userland)" - }, - "plugin_categories" : { - "type" : "array", - "description" : "categories of the plugin", - "items" : { - "$ref" : "#/components/schemas/StringList" - } - }, - "plugin_steps" : { - "type" : "array", - "description" : "steps of the plugin", - "items" : { - "$ref" : "#/components/schemas/StringList" - } - }, - "plugin_tags" : { - "type" : "array", - "description" : "tags of the plugin", - "items" : { - "$ref" : "#/components/schemas/StringList" - } - } - } - }, - "otoroshi.plugins.static.StaticResponse" : { - "description" : "Plugin that serves static responses", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.apikeys.CertificateAsApikey" : { - "description" : "Plugin to use a certificate as an apikey", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.GraphQLQueryConfig" : { - "description" : "???", - "type" : "object", - "properties" : { - "response_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "url" : { - "description" : "???", - "type" : "string" - }, - "response_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "???" - }, - "timeout" : { - "format" : "int64", - "description" : "???", - "type" : "integer" - }, - "query" : { - "description" : "???", - "type" : "string" - }, - "method" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.plugins.oidc.OIDCThirdPartyApiKeyConfigMode" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.ServiceGroup" : { - "description" : "The otoroshi model for a group of services", - "type" : "object", - "properties" : { - "id" : { - "description" : "A unique random string to identify your service", - "type" : "string" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "name" : { - "description" : "The name of your service. Only for debug and human readability purposes", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Just a bunch of random properties" - }, - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - } - } - }, - "otoroshi.auth.OAuth1Provider" : { - "description" : "Method used to get request and access token", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.XmlToJsonRequest" : { - "description" : "Plugin to transform xml body into json", - "type" : "object", - "properties" : { - "filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform http entity" - } - } - }, - "otoroshi.plugins.discovery.DiscoveryHelper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.ssl.pki.models.GenCsrQuery" : { - "description" : "Settings for generating a certificate", - "type" : "object", - "properties" : { - "client" : { - "description" : "Is cert client ?", - "type" : "boolean" - }, - "hosts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Certificate SANs" - }, - "key" : { - "description" : "Keypair specs", - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenKeyPairQuery" - }, - "includeAIA" : { - "description" : "Include AIA extension (if generated from otoroshi CA)", - "type" : "boolean" - }, - "signatureAlg" : { - "description" : "Signature algorithm", - "type" : "string" - }, - "existingSerialNumber" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "integer", - "format" : "int64" - } ], - "description" : "" - }, - "duration" : { - "description" : "Certificate lifespan", - "type" : "number" - }, - "digestAlg" : { - "description" : "Digest algo", - "type" : "string" - }, - "ca" : { - "description" : "Is cert ca ?", - "type" : "boolean" - }, - "name" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Certificate name" - }, - "subject" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Certificate subject" - } - } - }, - "otoroshi.next.plugins.NgApikeyMatcher" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "none_meta_keys_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on none metadata keys being present" - }, - "all_meta_keys_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on all metadata keys being present" - }, - "all_meta_in" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Matching on all metadata being present" - }, - "none_meta_in" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Matching on none metadata being present" - }, - "one_tag_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on one tag being present" - }, - "enabled" : { - "description" : "Tags and metadata matching enabled", - "type" : "boolean" - }, - "one_meta_in" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Matching on none metadata being present" - }, - "all_tags_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on all tags being present" - }, - "one_meta_key_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on one metadata being present" - }, - "none_tag_in" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching on none tags being present" - } - } - }, - "otoroshi.next.plugins.GraphQLBackendConfig" : { - "description" : "???", - "type" : "object", - "properties" : { - "schema" : { - "description" : "???", - "type" : "string" - }, - "permissions" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "???" - }, - "initial_data" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "???" - }, - "max_depth" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - } - } - }, - "otoroshi.plugins.apikeys.HasAllowedApiKeyValidator" : { - "description" : "Plugin that validates apikey", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.NetworkLocationMatch" : { - "description" : "Match a target if in the same network location", - "type" : "object", - "properties" : { - "rack" : { - "description" : "Rack name", - "type" : "string" - }, - "provider" : { - "description" : "Provider name", - "type" : "string" - }, - "dataCenter" : { - "description" : "Datacenter name", - "type" : "string" - }, - "zone" : { - "description" : "Zone name", - "type" : "string" - }, - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - }, - "region" : { - "description" : "Region name", - "type" : "string" - } - } - }, - "otoroshi.script.PluginType" : { - "type" : "string", - "enum" : [ "app", "transformer", "validator", "preroute", "sink", "listener", "job", "exporter" ], - "description" : "Plugin kind" - }, - "otoroshi.utils.mailer.ConsoleMailerSettings" : { - "description" : "Settings for the console mailer", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - } - } - }, - "otoroshi.plugins.oauth1.OAuth1CallerPlugin" : { - "description" : "Plugin to call OAuth1 protected backends", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.XmlToJsonResponse" : { - "description" : "Plugin to transform xml body into json", - "type" : "object", - "properties" : { - "filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform http entity" - } - } - }, - "otoroshi.models.DataExporterConfigType" : { - "type" : "string", - "enum" : [ "kafka", "pulsar", "elastic", "webhook", "file", "mailer", "custom", "none", "console", "metrics" ], - "description" : "Type of data exporter" - }, - "otoroshi.plugins.jobs.kubernetes.FailedCrdParsing" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "crd" : { - "description" : "The failed crd", - "type" : "object" - }, - "namespace" : { - "description" : "The namespace of the error", - "type" : "string" - }, - "pluralName" : { - "description" : "The plural name of the resources", - "type" : "string" - }, - "error" : { - "description" : "The actual error", - "type" : "string" - }, - "customizedSpec" : { - "description" : "The spec to customize", - "type" : "object" - } - } - }, - "otoroshi.script.Script" : { - "description" : "An otoroshi plugins stored as scala code in the otoroshi datastore", - "type" : "object", - "properties" : { - "name" : { - "description" : "The name of the script", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "desc" : { - "description" : "The description of the script", - "type" : "string" - }, - "code" : { - "description" : "The code of the script", - "type" : "string" - }, - "id" : { - "description" : "The id of the script", - "type" : "string" - }, - "type" : { - "description" : "Plugin type", - "$ref" : "#/components/schemas/otoroshi.script.PluginType" - } - } - }, - "otoroshi.next.plugins.MockEndpoint" : { - "description" : "???", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - }, - "body" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "???" - }, - "path" : { - "description" : "???", - "type" : "string" - }, - "resource" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "headers" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "???" - }, - "method" : { - "description" : "???", - "type" : "string" - }, - "resource_list" : { - "description" : "???", - "type" : "boolean" - } - } - }, - "otoroshi.storage.drivers.inmemory.S3Configuration" : { - "description" : "S3 bucket settings", - "type" : "object", - "properties" : { - "writeEvery" : { - "description" : "Write every n milliseconds", - "type" : "number" - }, - "chunkSize" : { - "format" : "int32", - "description" : "Upload chunk max size", - "type" : "integer" - }, - "bucket" : { - "description" : "Bucket name", - "type" : "string" - }, - "key" : { - "description" : "File path in bucket", - "type" : "string" - }, - "endpoint" : { - "description" : "Bucket endpoint", - "type" : "string" - }, - "v4auth" : { - "description" : "Use V4 auth", - "type" : "boolean" - }, - "access" : { - "description" : "Bucket access key", - "type" : "string" - }, - "secret" : { - "description" : "Bucket access secret", - "type" : "string" - }, - "region" : { - "description" : "Bucket region", - "type" : "string" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesToOtoroshiCertSyncJob" : { - "description" : "Plugin to sync otoroshi certificates with kubernetes", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.clientcert.SubIss" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "sn" : { - "description" : "The serial number of the current issuer", - "type" : "string" - }, - "subject" : { - "description" : "The subject DN", - "$ref" : "#/components/schemas/otoroshi.utils.http.DN" - }, - "issuer" : { - "description" : "The issuer DN", - "$ref" : "#/components/schemas/otoroshi.utils.http.DN" - } - } - }, - "otoroshi.utils.mailer.MailjetSettings" : { - "description" : "Settings for the mailjet mailer", - "type" : "object", - "properties" : { - "apiKeyPrivate" : { - "description" : "Private key", - "type" : "string" - }, - "apiKeyPublic" : { - "description" : "Public key", - "type" : "string" - }, - "to" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.EmailLocation" - }, - "description" : "Destination email address" - }, - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - } - } - }, - "play.api.libs.ws.WSProxyServer" : { - "type" : "object", - "properties" : { - "host" : { - "type" : "string", - "description" : "The hostname of the proxy server." - }, - "port" : { - "type" : "string", - "description" : "The port of the proxy server." - }, - "protocol" : { - "type" : "string", - "description" : "The protocol of the proxy server. Use \"http\" or \"https\". Defaults to \"http\" if not specified." - }, - "principal" : { - "type" : "string", - "description" : "The principal (aka username) of the credentials for the proxy server." - }, - "password" : { - "type" : "string", - "description" : "The password for the credentials for the proxy server." - }, - "ntlmDomain" : { - "type" : "string", - "description" : "The ntlm domain for the proxy server." - }, - "encoding" : { - "type" : "string", - "description" : "The realm's charset." - }, - "nonProxyHosts" : { - "type" : "string", - "description" : "The non proxied hosts" - } - }, - "description" : "Proxy server" - }, - "otoroshi.next.plugins.GlobalPerIpAddressThrottlingQuotas" : { - "description" : "Plugin for ip address quotas", - "type" : "object", - "properties" : { - "within" : { - "description" : "Is it within the quotas", - "type" : "boolean" - }, - "sec_calls" : { - "format" : "int64", - "description" : "Number of calls per second", - "type" : "integer" - } - } - }, - "otoroshi.plugins.loggers.BodyLoggerConfig" : { - "description" : "Configuration for BodyLogger", - "type" : "object", - "properties" : { - "json" : { - "description" : "The current config", - "type" : "object" - } - } - }, - "otoroshi.models.ServiceDescriptorIdentifier" : { - "type" : "string", - "description" : "the id of a service prefixed by 'service_'" - }, - "otoroshi.models.SecComHeaders" : { - "description" : "Header names for the otoroshi exchange protocol", - "type" : "object", - "properties" : { - "claimRequestName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name where the info token will be" - }, - "stateRequestName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name where the validation token will be" - }, - "stateResponseName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name where the validation token respondewill be" - } - } - }, - "otoroshi.auth.SAMLCredentials" : { - "description" : "Used to sign, encrypt assertions and sign SAML documents", - "type" : "object", - "properties" : { - "signingKey" : { - "description" : "Pair of configuration used to sign documents", - "$ref" : "#/components/schemas/otoroshi.auth.Credential" - }, - "encryptionKey" : { - "description" : "Pair of configuration used to encrypt assertions", - "$ref" : "#/components/schemas/otoroshi.auth.Credential" - }, - "signedDocuments" : { - "description" : "Indicates if SAML documents have to be sign before sending to identity provider", - "type" : "boolean" - }, - "encryptedAssertions" : { - "description" : "Indicates if assertions have to be encrypt before sending to identity provider", - "type" : "boolean" - } - } - }, - "otoroshi.next.models.StoredNgTarget" : { - "description" : "A target that can be stored in the otoroshi datastore", - "type" : "object", - "properties" : { - "name" : { - "description" : "The name of the target", - "type" : "string" - }, - "_loc" : { - "description" : "The location of the target", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The metadata of the target" - }, - "description" : { - "description" : "The description of the target", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The tags of the target" - }, - "id" : { - "description" : "The id of the target", - "type" : "string" - }, - "target" : { - "description" : "The actual target", - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - } - } - }, - "otoroshi.next.plugins.NgApikeyExtractorCustomHeaders" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Is it enabled", - "type" : "boolean" - }, - "client_id_header_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to extract client id" - }, - "client_secret_header_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to extract client secret" - } - } - }, - "otoroshi.tcp.TlsMode" : { - "type" : "string", - "enum" : [ "Disabled", "Enabled", "PassThrough" ], - "description" : "TLS mode" - }, - "otoroshi.models.ESKPAlgoSettings" : { - "description" : "Settings to use elliptic curve signing algorithm from a certificate keypair", - "type" : "object", - "properties" : { - "size" : { - "format" : "int32", - "description" : "Size of the key", - "type" : "integer" - }, - "certId" : { - "description" : "Certificate id to use the keypair", - "type" : "string" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.plugins.users.HasAllowedUsersValidator" : { - "description" : "Plugin that validates current user", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.S3BackendConfig" : { - "description" : "???", - "type" : "object", - "properties" : { - "s3" : { - "description" : "???", - "$ref" : "#/components/schemas/otoroshi.storage.drivers.inmemory.S3Configuration" - } - } - }, - "otoroshi.next.models.NgTreeRouter" : { - "description" : "A very efficient router with a tree structure", - "type" : "object", - "properties" : { } - }, - "AuditEventList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.events.AuditEvent" - } - }, - "otoroshi.next.plugins.NgCorsSettings" : { - "description" : "Configuration for Cors", - "type" : "object", - "properties" : { - "allow_credentials" : { - "description" : "Allowed credentials", - "type" : "boolean" - }, - "max_age" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "number" - } ], - "description" : "cors max age" - }, - "allow_origin" : { - "description" : "Allowed cors origins", - "type" : "string" - }, - "allow_methods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed cors methods" - }, - "excluded_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths without cors" - }, - "allow_headers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed cors headers" - }, - "expose_headers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Exposed cors headers" - } - } - }, - "otoroshi.models.ServiceDescriptor" : { - "description" : "The otoroshi model for a service (handles routing)", - "type" : "object", - "properties" : { - "buildMode" : { - "description" : "Display a construction page when a user try to use the service", - "type" : "boolean" - }, - "hosts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Possible hosts for the service" - }, - "privateApp" : { - "description" : "When enabled, user will be allowed to use the service (UI) only if they are registered users of the private apps domain", - "type" : "boolean" - }, - "localScheme" : { - "description" : "The scheme used localy, mainly http", - "type" : "string" - }, - "authConfigRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "A reference to a global auth module config" - }, - "issueCertCA" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "CA for cert issuance" - }, - "root" : { - "description" : "Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar", - "type" : "string" - }, - "name" : { - "description" : "The name of your service. Only for debug and human readability purposes", - "type" : "string" - }, - "additionalHeaders" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be added to each client request. Useful to add authentication" - }, - "domain" : { - "description" : "The domain on which the service is available.", - "type" : "string" - }, - "clientConfig" : { - "description" : "Http client settings", - "$ref" : "#/components/schemas/otoroshi.models.ClientConfig" - }, - "matchingRoot" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The root path on which the service is available" - }, - "forceHttps" : { - "description" : "Will force redirection to https:// if not present", - "type" : "boolean" - }, - "localHost" : { - "description" : "The host used localy, mainly localhost:xxxx", - "type" : "string" - }, - "sendOtoroshiHeadersBack" : { - "description" : "When enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc ...", - "type" : "boolean" - }, - "healthCheck" : { - "description" : "Healthcheck settings", - "$ref" : "#/components/schemas/otoroshi.models.HealthCheck" - }, - "strictlyPrivate" : { - "description" : "When strictly private, private app session will not pass apikey filters", - "type" : "boolean" - }, - "detectApiKeySooner" : { - "description" : "Detect if an apikey is present but do not fail if not", - "type" : "boolean" - }, - "allowHttp10" : { - "description" : "Allow HTTP/1.0 requests", - "type" : "boolean" - }, - "subdomain" : { - "description" : "The subdomain on which the service is available", - "type" : "string" - }, - "paths" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Matching paths on request" - }, - "stripPath" : { - "description" : "Strip matching path in the forwarded request path", - "type" : "boolean" - }, - "secComAlgoChallengeOtoToBack" : { - "description" : "Algorithm to sign challenge token to the backend", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "apiKeyConstraints" : { - "description" : "Routing and extraction constraints for the apikeyh", - "$ref" : "#/components/schemas/otoroshi.models.ApiKeyConstraints" - }, - "env" : { - "description" : "The line on which the service is available. Based on that value, the name of the line will be appended to the subdomain. For line prod, nothing will be appended. For example, if the subdomain is 'foo' and line is 'preprod', then the exposed service will be available at 'foo.preprod.mydomain'", - "type" : "string" - }, - "xForwardedHeaders" : { - "description" : "Send X-Forwarded-* headers", - "type" : "boolean" - }, - "transformerRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Enabled transformer plugins" - }, - "enabled" : { - "description" : "Activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist", - "type" : "boolean" - }, - "gzip" : { - "description" : "GZIP settings", - "$ref" : "#/components/schemas/otoroshi.utils.gzip.GzipConfig" - }, - "sendInfoToken" : { - "description" : "Should otoroshi send info token", - "type" : "boolean" - }, - "tcpUdpTunneling" : { - "description" : "Enabled TCP/UDP tunneling through websocket connection", - "type" : "boolean" - }, - "removeHeadersOut" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Remove headers on client response" - }, - "useAkkaHttpClient" : { - "description" : "Use akka http client for this service", - "type" : "boolean" - }, - "maintenanceMode" : { - "description" : "Display a maintainance page when a user try to use the service", - "type" : "boolean" - }, - "id" : { - "description" : "A unique random string to identify your service", - "type" : "string" - }, - "removeHeadersIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Remove headers on client request" - }, - "logAnalyticsOnServer" : { - "description" : "Log analytics event on the server", - "type" : "boolean" - }, - "secComAlgoInfoToken" : { - "description" : "Algorithm to verify/sign challenge token coming from/to the backend", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "userFacing" : { - "description" : "The fact that this service will be seen by users and cannot be impacted by the Snow Monkey", - "type" : "boolean" - }, - "transformerConfig" : { - "description" : "Transformer plugins configuration", - "type" : "object" - }, - "clientValidatorRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "A reference to validation authority" - }, - "securityExcludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Exclude some paths" - }, - "ipFiltering" : { - "description" : "Ip filtering settings", - "$ref" : "#/components/schemas/otoroshi.models.IpFiltering" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - }, - "description" : "The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures" - }, - "redirection" : { - "description" : "Redirection settings", - "$ref" : "#/components/schemas/otoroshi.models.RedirectionSettings" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "restrictions" : { - "description" : "Restriction settings", - "$ref" : "#/components/schemas/otoroshi.models.Restrictions" - }, - "overrideHost" : { - "description" : "Host header will be overriden with Host of the target", - "type" : "boolean" - }, - "accessValidator" : { - "description" : "Service access validatiors", - "$ref" : "#/components/schemas/otoroshi.script.AccessValidatorRef" - }, - "sendStateChallenge" : { - "description" : "Should otoroshi send challenge token", - "type" : "boolean" - }, - "chaosConfig" : { - "description" : "Chaos engineering settings", - "$ref" : "#/components/schemas/otoroshi.models.ChaosConfig" - }, - "secComInfoTokenVersion" : { - "description" : "Version of the info token", - "$ref" : "#/components/schemas/otoroshi.models.SecComInfoTokenVersion" - }, - "additionalHeadersOut" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be added to each client response" - }, - "secComHeaders" : { - "description" : "Header names for sec. com. protocol", - "$ref" : "#/components/schemas/otoroshi.models.SecComHeaders" - }, - "matchingHeaders" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that MUST be present on client request to route it. Useful to implement versioning" - }, - "secComAlgoChallengeBackToOto" : { - "description" : "Algorithm to verify challenge token coming from the backend", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "secComUseSameAlgo" : { - "description" : "Use the same algo for info token, challenge token signing, challenge token verification", - "type" : "boolean" - }, - "useNewWSClient" : { - "description" : "Use akka http client for this service on websocket calls", - "type" : "boolean" - }, - "secComExcludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "URI patterns excluded from secured communications" - }, - "redirectToLocal" : { - "description" : "If you work locally with Otoroshi, you may want to use that feature to redirect one particuliar service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests", - "type" : "boolean" - }, - "enforceSecureCommunication" : { - "description" : "When enabled, Otoroshi will try to exchange headers with backend service to ensure no one else can use the service from outside", - "type" : "boolean" - }, - "missingOnlyHeadersOut" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Add header on client response if they are not present" - }, - "secComSettings" : { - "description" : "Sec. com. settings", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "handleLegacyDomain" : { - "description" : "Use 'domain', 'subdomain', 'env' and 'matchingRoot' for routing in addition to hosts, or just use hosts.", - "type" : "boolean" - }, - "canary" : { - "description" : "Canary settings", - "$ref" : "#/components/schemas/otoroshi.models.Canary" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "plugins" : { - "description" : "Plugins enabled for this service. will replace separate plugins fields in a near future", - "$ref" : "#/components/schemas/otoroshi.script.plugins.Plugins" - }, - "secComTtl" : { - "description" : "TTL for the info token", - "type" : "number" - }, - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "secComVersion" : { - "description" : "Version of the sec. com.", - "$ref" : "#/components/schemas/otoroshi.models.SecComVersion" - }, - "preRouting" : { - "description" : "Pre routing plugin settings", - "$ref" : "#/components/schemas/otoroshi.script.PreRoutingRef" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Each service descriptor is attached to groups. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group" - }, - "readOnly" : { - "description" : "Service only accepts GET, HEAD and OPTIONS requests", - "type" : "boolean" - }, - "privatePatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "If you define a public pattern that is a little bit too much, you can make some of public URL private again" - }, - "targetsLoadBalancing" : { - "description" : "Loadbalancing strategy", - "$ref" : "#/components/schemas/otoroshi.models.LoadBalancing" - }, - "cors" : { - "description" : "CORS settings", - "$ref" : "#/components/schemas/otoroshi.models.CorsSettings" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Just a bunch of random properties" - }, - "publicPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "By default, every services are private only and you'll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use '/.*'" - }, - "api" : { - "description" : "Api exposition settings", - "$ref" : "#/components/schemas/otoroshi.models.ApiDescriptor" - }, - "missingOnlyHeadersIn" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Add header on client request if they are not present" - }, - "issueCert" : { - "description" : "Flag to automatically issue a cert for this service", - "type" : "boolean" - }, - "headersVerification" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be verified after routing." - }, - "jwtVerifier" : { - "description" : "JWT verifiers settings", - "$ref" : "#/components/schemas/otoroshi.models.JwtVerifier" - }, - "letsEncrypt" : { - "description" : "Flag to automatically issue a let's encrypt (ACME) cert for this service", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.UdpTunnel" : { - "description" : "Plugin to have udp tunnels over websockets", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.izanami.IzanamiCanaryConfig" : { - "description" : "Configuration for IzanamiCanary", - "type" : "object", - "properties" : { - "izanamiClientId" : { - "description" : "Izanami client id", - "type" : "string" - }, - "configId" : { - "description" : "Id of the target izanami configuration", - "type" : "string" - }, - "experimentId" : { - "description" : "Id of the target izanami experiment", - "type" : "string" - }, - "mtls" : { - "description" : "Izanami server tls config", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "izanamiUrl" : { - "description" : "Izanami server url", - "type" : "string" - }, - "timeout" : { - "description" : "Timeout when talking to the izanami server", - "type" : "number" - }, - "izanamiClientSecret" : { - "description" : "Izanami client secret", - "type" : "string" - }, - "routeConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "The actual routing config" - } - } - }, - "otoroshi.next.plugins.RemoveHeadersIn" : { - "description" : "Plugin to remove headers from request", - "type" : "object", - "properties" : { - "names" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Name of removed headers in request" - } - } - }, - "otoroshi.next.plugins.RobotConfig" : { - "description" : "Configuration for Robots", - "type" : "object", - "properties" : { - "robot_txt_content" : { - "description" : "Content of /robots.txt", - "type" : "string" - }, - "meta_content" : { - "description" : "content of the tag", - "type" : "string" - }, - "robot_enabled" : { - "description" : "/robots.txt enabled", - "type" : "boolean" - }, - "header_content" : { - "description" : "Content of the X-Robots-Tag headers", - "type" : "string" - }, - "header_enabled" : { - "description" : "Header enabled", - "type" : "boolean" - }, - "meta_enabled" : { - "description" : "Meta tag enabled", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesSupport" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.metrics.PrometheusEndpoint" : { - "description" : "Plugin to expose metrics collected by PrometheusServiceMetrics", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.wrappers.PreRoutingWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.TeamAccess" : { - "description" : "Access rights for teams", - "type" : "object", - "properties" : { - "canRead" : { - "description" : "Can this access right read data", - "type" : "boolean" - }, - "value" : { - "description" : "Access pattern", - "type" : "string" - }, - "canWrite" : { - "description" : "Can this access right write data", - "type" : "boolean" - } - } - }, - "otoroshi.models.OtoroshiAdminType" : { - "type" : "string", - "enum" : [ "SIMPLE", "WEBAUTHN" ], - "description" : "Admin kind" - }, - "otoroshi.plugins.log4j.Log4jExpressionParser" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.ssl.Cert" : { - "description" : "The otoroshi model for X509 certificates", - "type" : "object", - "properties" : { - "certType" : { - "type" : "string", - "description" : "the kind of certificate", - "enum" : [ "client", "ca", "letsEncrypt", "keypair", "selfSigned", "certificate" ] - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "subject" : { - "description" : "Certificate subject", - "type" : "string" - }, - "letsEncrypt" : { - "description" : "Let's encrypt (ACME) generated", - "type" : "boolean" - }, - "keypair" : { - "description" : "Is cert used for its keypair only ?", - "type" : "boolean" - }, - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "revoked" : { - "description" : "Certificate is revoked", - "type" : "boolean" - }, - "valid" : { - "description" : "Is cert valid", - "type" : "boolean" - }, - "password" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Certificate password" - }, - "autoRenew" : { - "description" : "Auto renew cert", - "type" : "boolean" - }, - "exposed" : { - "description" : "Is the cert exposed (public key exposed in jwks.json)", - "type" : "boolean" - }, - "client" : { - "description" : "Is cert a client cert ?", - "type" : "boolean" - }, - "from" : { - "description" : "Start date", - "type" : "number" - }, - "selfSigned" : { - "description" : "Is cert self signed", - "type" : "boolean" - }, - "id" : { - "description" : "Entity id", - "type" : "string" - }, - "ca" : { - "description" : "Is cert a CA ?", - "type" : "boolean" - }, - "chain" : { - "description" : "Certicates chain (PEM encoded)", - "type" : "string" - }, - "sans" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Certificate SANs" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "privateKey" : { - "description" : "Certificate private key (PEM encoded)", - "type" : "string" - }, - "caRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Reference to the CA (if any)" - }, - "domain" : { - "description" : "Certificate domain", - "type" : "string" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "to" : { - "description" : "Stop date", - "type" : "number" - } - } - }, - "otoroshi.models.AlgoSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ESKPAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.JWKSAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.KidAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.RSAKPAlgoSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.RSAlgoSettings" - } ] - }, - "otoroshi.tcp.TcpRule" : { - "description" : "Associate targets for a domain (SNI)", - "type" : "object", - "properties" : { - "domain" : { - "description" : "match on SNI domain", - "type" : "string" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpTarget" - }, - "description" : "TCP targets" - } - } - }, - "otoroshi.plugins.geoloc.MaxMindGeolocationHelper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.IngressSupport" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.utils.TypedMap" : { - "description" : "A map with typed keys", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.CleverCloudSettings" : { - "description" : "Settings for connection to the clever-cloud api", - "type" : "object", - "properties" : { - "consumerSecret" : { - "description" : "Clever-Cloud oauth consumer secret", - "type" : "string" - }, - "consumerKey" : { - "description" : "Clever-Cloud oauth consumer key", - "type" : "string" - }, - "secret" : { - "description" : "Clever-Cloud oauth secret", - "type" : "string" - }, - "token" : { - "description" : "Clever-Cloud oauth token", - "type" : "string" - }, - "orgaId" : { - "description" : "Clever-Cloud organization id", - "type" : "string" - } - } - }, - "otoroshi.plugins.hmac.HMACCallerPlugin" : { - "description" : "Plugin that can call an hmac protected backend", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.AllowHttpMethods" : { - "description" : "Plugin that only allow calls with specific http methods", - "type" : "object", - "properties" : { - "allowed" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of allowed methods" - }, - "forbidden" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of forbidden methods" - } - } - }, - "otoroshi.plugins.apikeys.ClientCredentialFlow" : { - "description" : "Plugin that provide the OAuth2 client_credentials flow", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.JsonTransform" : { - "description" : "Plugin to transform json response", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.OtoroshiResourcesContext" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "routes" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - }, - "description" : "template for entities routes" - }, - "apiKeys" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - }, - "description" : "template for entities apiKeys" - }, - "backends" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgBackend" - }, - "description" : "template for entities backends" - }, - "scripts" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.script.Script" - }, - "description" : "template for entities scripts" - }, - "jwtVerifiers" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - }, - "description" : "template for entities jwtVerifiers" - }, - "tenants" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Tenant" - }, - "description" : "template for entities tenants" - }, - "dataExporters" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfig" - }, - "description" : "template for entities dataExporters" - }, - "teams" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Team" - }, - "description" : "template for entities teams" - }, - "services" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgService" - }, - "description" : "template for entities services" - }, - "serviceDescriptors" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - }, - "description" : "template for entities serviceDescriptors" - }, - "globalConfigs" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GlobalConfig" - }, - "description" : "template for entities globalConfigs" - }, - "authModules" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.AuthModuleConfig" - }, - "description" : "template for entities authModules" - }, - "tcpServices" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpService" - }, - "description" : "template for entities tcpServices" - }, - "certificates" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.ssl.Cert" - }, - "description" : "template for entities certificates" - }, - "simpleAdmins" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - }, - "description" : "template for entities simpleAdmins" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.StoredNgTarget" - }, - "description" : "template for entities targets" - }, - "serviceGroups" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroup" - }, - "description" : "template for entities serviceGroups" - } - } - }, - "otoroshi.models.Canary" : { - "description" : "Settings for canary routing", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Use canary mode for this service", - "type" : "boolean" - }, - "traffic" : { - "format" : "double", - "description" : "Ratio of traffic that will be sent to canary targets.", - "type" : "number" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - }, - "description" : "The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures" - }, - "root" : { - "description" : "Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgRouteDomainAndPathWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "route" : { - "description" : "The current route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - }, - "domain" : { - "description" : "The current domain of the route", - "type" : "string" - }, - "path" : { - "description" : "The current of the route", - "type" : "string" - } - } - }, - "otoroshi.plugins.biscuit.BiscuitToken" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.BadResponse" : { - "description" : "Settings for a bad response return (chaos engineering)", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "The HTTP status for the response", - "type" : "integer" - }, - "body" : { - "description" : "The body of the HTTP response", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The HTTP headers of the response" - } - } - }, - "otoroshi.next.plugins.wrappers.RequestSinkWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.CanaryMode" : { - "description" : "Plugin for canary mode", - "type" : "object", - "properties" : { - "traffic" : { - "format" : "double", - "description" : "Which percentage of the traffic goes to the canary target", - "type" : "number" - }, - "root" : { - "description" : "The root path for target", - "type" : "string" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - }, - "description" : "The canary targets" - } - } - }, - "otoroshi.plugins.clientcert.HasClientCertMatchingApikeyValidator" : { - "description" : "Plugin that validates client certificates", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.authcallers.BasicAuthCallerConfig" : { - "description" : "Configuration for BasicAuthCaller", - "type" : "object", - "properties" : { - "username" : { - "description" : "Expected username", - "type" : "string" - }, - "password" : { - "description" : "Expected password", - "type" : "string" - }, - "headerName" : { - "description" : "Expected header name", - "type" : "string" - }, - "headerValueFormat" : { - "description" : "Expected header format (to handle 'Basic ')", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.RemoveHeadersOut" : { - "description" : "Plugin to remove headers from response", - "type" : "object", - "properties" : { - "names" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Name of removed headers in response" - } - } - }, - "otoroshi.env.Env" : { - "description" : "The main otoroshi technical context containing everything to make otoroshi work", - "type" : "object", - "properties" : { - "circuitBeakersHolder" : { - "description" : "The current instance of circuit breakers holder", - "$ref" : "#/components/schemas/otoroshi.gateway.CircuitBreakersHolder" - } - } - }, - "otoroshi.plugins.jwt.JwtUserExtractor" : { - "description" : "Plugin to extract user from jwt token", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgRoute" : { - "description" : "A routing primitive representing how a request is matched and where the request is forwarded", - "type" : "object", - "properties" : { - "debug_flow" : { - "description" : "Enable report debugging", - "type" : "boolean" - }, - "enabled" : { - "description" : "Is the route enabled", - "type" : "boolean" - }, - "name" : { - "description" : "The name of the route", - "type" : "string" - }, - "id" : { - "description" : "The ud of the route", - "type" : "string" - }, - "export_reporting" : { - "description" : "Export the execution reporting through standard data exporter", - "type" : "boolean" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The metadata of the route" - }, - "frontend" : { - "description" : "The frontend of the route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgFrontend" - }, - "_loc" : { - "description" : "The location of the route", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The tags of the route" - }, - "capture" : { - "description" : "Capture http traffic", - "type" : "boolean" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The groups of the route" - }, - "backend_ref" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The backend id of the route (if one)" - }, - "description" : { - "description" : "The description of the route", - "type" : "string" - }, - "backend" : { - "description" : "The backend of the route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgBackend" - } - } - }, - "otoroshi.auth.SAMLSignatureAlgorithm" : { - "description" : "Algorithm to sign SAML requests", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.ForceHttpsTraffic" : { - "description" : "Plugin to force https", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.GlobalConfig" : { - "description" : "The global config (dynamic) for otoroshi", - "type" : "object", - "properties" : { - "geolocationSettings" : { - "description" : "Settings for geolocation extraction", - "$ref" : "#/components/schemas/otoroshi.models.GeolocationSettings" - }, - "alertsEmails" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Email addresses that will receive all Otoroshi alert events" - }, - "throttlingQuota" : { - "format" : "int64", - "description" : "Authorized number of calls per second globally, measured on 10 seconds", - "type" : "integer" - }, - "maxWebhookSize" : { - "format" : "int32", - "description" : "Max number of items in webhooks", - "type" : "integer" - }, - "maxConcurrentRequests" : { - "format" : "int64", - "description" : "The number of authorized request processed at the same time", - "type" : "integer" - }, - "cleverSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.CleverCloudSettings" - } ], - "description" : "Optional CleverCloud configuration" - }, - "templates" : { - "description" : "The otoroshi default templates for entities", - "$ref" : "#/components/schemas/otoroshi.models.DefaultTemplates" - }, - "endlessIpAddresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "IP addresses for which any request to Otoroshi will respond with 128 Gb of zeros" - }, - "plugins" : { - "description" : "global plugins settings", - "$ref" : "#/components/schemas/otoroshi.script.plugins.Plugins" - }, - "kafkaConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.events.KafkaConfig" - } ], - "description" : "Global kafka settings. deprecated" - }, - "maxLogsSize" : { - "format" : "int32", - "description" : "Number of events kept locally", - "type" : "integer" - }, - "proxies" : { - "description" : "Web proxies settings", - "$ref" : "#/components/schemas/otoroshi.models.Proxies" - }, - "enableEmbeddedMetrics" : { - "description" : "Enable embedded metrics", - "type" : "boolean" - }, - "elasticReadsConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ElasticAnalyticsConfig" - } ], - "description" : "Config. for elastic reads" - }, - "trustXForwarded" : { - "description" : "Use X-Forwarded-* headers for routing", - "type" : "boolean" - }, - "quotasSettings" : { - "description" : "Settings to generate alert when an apikey almost exceeded or exceeded its quotas", - "$ref" : "#/components/schemas/otoroshi.models.QuotasAlmostExceededSettings" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "limitConcurrentRequests" : { - "description" : "If enabled, Otoroshi will reject new request if too much at the same time", - "type" : "boolean" - }, - "useAkkaHttpClient" : { - "description" : "Globally use akka http client for everything", - "type" : "boolean" - }, - "elasticWritesConfigs" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.ElasticAnalyticsConfig" - }, - "description" : "Configs. for Elastic writes" - }, - "logAnalyticsOnServer" : { - "description" : "Log analytics event on the server", - "type" : "boolean" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "apiReadOnly" : { - "description" : "If enabled, Admin API won't be able to write/update/delete entities", - "type" : "boolean" - }, - "backOfficeAuthRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Id of the auth module used for otoroshi-ui login" - }, - "streamEntityOnly" : { - "description" : "HTTP will be streamed only. Doesn't work with old browsers", - "type" : "boolean" - }, - "otoroshiId" : { - "description" : "Unique id for this otoroshi instance", - "type" : "string" - }, - "mailerSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailerSettings" - } ], - "description" : "Optional mailer configuration" - }, - "lines" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Possibles lines for Otoroshi" - }, - "middleFingers" : { - "description" : "Use middle finger emoji as a response character for endless HTTP responses", - "type" : "boolean" - }, - "analyticsWebhooks" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Webhook" - }, - "description" : "Webhook that will receive all internal Otoroshi events" - }, - "autoCert" : { - "description" : "Auto certs settings", - "$ref" : "#/components/schemas/otoroshi.models.AutoCert" - }, - "maintenanceMode" : { - "description" : "Global maintenant mode", - "type" : "boolean" - }, - "letsEncryptSettings" : { - "description" : "Let's encrypt (ACME) settings", - "$ref" : "#/components/schemas/otoroshi.utils.letsencrypt.LetsEncryptSettings" - }, - "snowMonkeyConfig" : { - "description" : "Snowmonky settings", - "$ref" : "#/components/schemas/otoroshi.models.SnowMonkeyConfig" - }, - "scripts" : { - "description" : "global plugins settings. will be deprecated soon", - "$ref" : "#/components/schemas/otoroshi.models.GlobalScripts" - }, - "perIpThrottlingQuota" : { - "format" : "int64", - "description" : "Authorized number of calls per second globally per IP address, measured on 10 seconds", - "type" : "integer" - }, - "useCircuitBreakers" : { - "description" : "If enabled, services will be authorized to use circuit breakers", - "type" : "boolean" - }, - "maxHttp10ResponseSize" : { - "format" : "int64", - "description" : "The max size in bytes of an HTTP 1.0 response", - "type" : "integer" - }, - "tlsSettings" : { - "description" : "TLS settings", - "$ref" : "#/components/schemas/otoroshi.models.TlsSettings" - }, - "statsdConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.events.StatsdConfig" - } ], - "description" : "Statsd settings (agent connection)" - }, - "autoLinkToDefaultGroup" : { - "description" : "If not defined, every new service descriptor will be added to the default group", - "type" : "boolean" - }, - "alertsWebhooks" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Webhook" - }, - "description" : "Webhook that will receive all Otoroshi alert events" - }, - "ipFiltering" : { - "description" : "Global ip filtering settings", - "$ref" : "#/components/schemas/otoroshi.models.IpFiltering" - }, - "u2fLoginOnly" : { - "description" : "If enabled, login to backoffice through Auth0 will be disabled", - "type" : "boolean" - }, - "userAgentSettings" : { - "description" : "Settings for useragent extraction", - "$ref" : "#/components/schemas/otoroshi.models.UserAgentSettings" - } - } - }, - "otoroshi.next.plugins.BuildMode" : { - "description" : "Plugin for build more", - "type" : "object", - "properties" : { } - }, - "StringList" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "otoroshi.plugins.discovery.DiscoverySelfRegistrationSink" : { - "description" : "Plugin that add services discovery to otoroshi", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.ExporterRef" : { - "description" : "Ref to an exporter id", - "type" : "object", - "properties" : { - "ref" : { - "description" : "Reference to an exporter", - "type" : "string" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "config" : { - "description" : "Exporter config.", - "type" : "object" - } - } - }, - "otoroshi.ssl.pki.models.GenKeyPairQuery" : { - "description" : "Settings for generating a keypair", - "type" : "object", - "properties" : { - "algo" : { - "description" : "Keypair algorithm", - "type" : "string" - }, - "size" : { - "format" : "int32", - "description" : "Keypair size", - "type" : "integer" - } - } - }, - "otoroshi.next.plugins.NgRestrictionPath" : { - "description" : "Configuration for NgRestrictions", - "type" : "object", - "properties" : { - "method" : { - "description" : "The http method (can be *)", - "type" : "string" - }, - "path" : { - "description" : "The request path (can include domain)", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.NgFaultConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { } - }, - "HealthCheckEventList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.events.HealthCheckEvent" - } - }, - "otoroshi.next.plugins.FileUtils" : { - "description" : "???", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.ReadOnlyCalls" : { - "description" : "Plugin for readonly calls", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.QueryTransformerConfig" : { - "description" : "Configuration for QueryTransformer", - "type" : "object", - "properties" : { - "remove" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Remove query params" - }, - "rename" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Rename query params to" - } - } - }, - "otoroshi.next.plugins.GraphQLBackend" : { - "description" : "???", - "type" : "object", - "properties" : { - "schema" : { - "description" : "???", - "type" : "string" - }, - "permissions" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "???" - }, - "initial_data" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "???" - }, - "max_depth" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - } - } - }, - "otoroshi.next.models.NgFrontend" : { - "description" : "Representation of how a request will be matched to a route", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "the headers that will be matched" - }, - "query" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "the query params that will be matched" - }, - "domains" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgDomainAndPath" - }, - "description" : "The domain and path that will be matched" - }, - "methods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "the http methods that will be matched" - }, - "exact" : { - "description" : "Match on exact path ?", - "type" : "boolean" - }, - "strip_path" : { - "description" : "Is path stripped from backend request", - "type" : "boolean" - } - } - }, - "otoroshi.next.models.StoredNgTargetDataStore" : { - "description" : "The datastore for targets", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.OutageStrategy" : { - "type" : "string", - "enum" : [ "AllServicesPerGroup", "OneServicePerGroup" ] - }, - "otoroshi.next.plugins.MockResponsesConfig" : { - "description" : "Configuration for MockResponses", - "type" : "object", - "properties" : { - "responses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockResponse" - }, - "description" : "Possible responses" - }, - "pass_through" : { - "description" : "Pass the call if no mocked response found", - "type" : "boolean" - }, - "form_data" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockFormData" - } ], - "description" : "???" - } - } - }, - "otoroshi.models.ClientIdAuthConstraints" : { - "description" : "Settings to extract apikey (using client_id only) from a header or query param", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Constraint enabled", - "type" : "boolean" - }, - "headerName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to find client_id" - }, - "queryName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Query param name to find client_id" - } - } - }, - "otoroshi.auth.BasicAuthUser" : { - "description" : "A user model for the BasicAuthModuleConfig module", - "type" : "object", - "properties" : { - "metadata" : { - "description" : "User metadata", - "type" : "object" - }, - "password" : { - "description" : "User password (bcrypt hashed)", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "User tags" - }, - "email" : { - "description" : "User email", - "type" : "string" - }, - "webauthn" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.WebAuthnDetails" - } ], - "description" : "Webauthn details" - }, - "rights" : { - "description" : "User rights", - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "name" : { - "description" : "User name", - "type" : "string" - } - } - }, - "otoroshi.models.ClientConfig" : { - "description" : "Settings for the http client when http request is forwarded", - "type" : "object", - "properties" : { - "connectionTimeout" : { - "format" : "int64", - "description" : "Timeout at connection", - "type" : "integer" - }, - "useCircuitBreaker" : { - "description" : "Use a circuit breaker to avoid cascading failure when calling chains of services. Highly recommended !", - "type" : "boolean" - }, - "retryInitialDelay" : { - "format" : "int64", - "description" : "Specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor", - "type" : "integer" - }, - "cacheConnectionSettings" : { - "description" : "Cached connection settings", - "$ref" : "#/components/schemas/otoroshi.utils.http.CacheConnectionSettings" - }, - "proxy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy settings for http client" - }, - "callTimeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (soft timeout as it's enforced by the circuit breaker)", - "type" : "integer" - }, - "callAndStreamTimeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (hard timeout, connection will be closed after that duration)", - "type" : "integer" - }, - "globalTimeout" : { - "format" : "int64", - "description" : "Specify how long the global call (with retries) should last at most in milliseconds", - "type" : "integer" - }, - "maxErrors" : { - "format" : "int32", - "description" : "Specify how many errors can pass before opening the circuit breaker", - "type" : "integer" - }, - "retries" : { - "format" : "int32", - "description" : "Specify how many times the client will try to fetch the result of the request after an error before giving up.", - "type" : "integer" - }, - "backoffFactor" : { - "format" : "int64", - "description" : "Specify the factor to multiply the delay for each retry", - "type" : "integer" - }, - "customTimeouts" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.CustomTimeouts" - }, - "description" : "Custom timeouts per path" - }, - "idleTimeout" : { - "format" : "int64", - "description" : "Timeout on idle connection", - "type" : "integer" - }, - "sampleInterval" : { - "format" : "int64", - "description" : "Specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted", - "type" : "integer" - } - } - }, - "otoroshi.next.plugins.NgBadResponse" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "status of the response", - "type" : "integer" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "headers of the response" - }, - "body" : { - "description" : "Body of the response", - "type" : "string" - } - } - }, - "otoroshi.plugins.useragent.UserAgentInfoEndpoint" : { - "description" : "Plugin that return user-agent infos on an endpoint", - "type" : "object", - "properties" : { } - }, - "LiveStats" : { - "type" : "object", - "description" : "Service live stats" - }, - "otoroshi.models.ApiKeyConstraints" : { - "description" : "Settings used to extract apikeys from http requests and routing traffic", - "type" : "object", - "properties" : { - "customHeadersAuth" : { - "description" : "Settings to extract apikey from custom headers", - "$ref" : "#/components/schemas/otoroshi.models.CustomHeadersAuthConstraints" - }, - "routing" : { - "description" : "Routing settings for this apikey", - "$ref" : "#/components/schemas/otoroshi.models.ApiKeyRouteMatcher" - }, - "clientIdAuth" : { - "description" : "Settings to extract client_id only apikey", - "$ref" : "#/components/schemas/otoroshi.models.ClientIdAuthConstraints" - }, - "jwtAuth" : { - "description" : "Settings to extract apikey from jwt token", - "$ref" : "#/components/schemas/otoroshi.models.JwtAuthConstraints" - }, - "basicAuth" : { - "description" : "Settings to extract basic auth style apikey", - "$ref" : "#/components/schemas/otoroshi.models.BasicAuthConstraints" - } - } - }, - "otoroshi.plugins.metrics.ServiceMetrics" : { - "description" : "Plugin to collect service metrics", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.core.apikeys.BasicAuthApikeyExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.izanami.IzanamiCanary" : { - "description" : "Plugin that can route on different target paths based on an izanami experiment", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgOtoroshiChallengeConfig" : { - "description" : "Configuration for OtoroshiChallenge", - "type" : "object", - "properties" : { - "version" : { - "description" : "The version of the jwt", - "$ref" : "#/components/schemas/otoroshi.models.SecComVersion" - }, - "ttl" : { - "description" : "The ttl of the generated jwt in milliseconds", - "type" : "number" - }, - "request_header_name" : { - "description" : "The header name to inject the jwt", - "type" : "string" - }, - "response_header_name" : { - "description" : "The header name to read the jwt", - "type" : "string" - }, - "algo_to_backend" : { - "description" : "The jwt signing algorithm when writing", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "algo_from_backend" : { - "description" : "The jwt signing algorithm when reading", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "state_resp_leeway" : { - "description" : "the number of seconds acceptable between client and server time", - "type" : "number" - } - } - }, - "otoroshi.plugins.mirror.MirroringPlugin" : { - "description" : "Plugin to mirror calls", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgOtoroshiInfoConfig" : { - "description" : "Configuration for OtoroshiInfos", - "type" : "object", - "properties" : { - "version" : { - "description" : "The version of the jwt", - "$ref" : "#/components/schemas/otoroshi.models.SecComInfoTokenVersion" - }, - "secComTtl" : { - "description" : "The ttl of the generated jwt in milliseconds", - "type" : "number" - }, - "headerName" : { - "description" : "The header name to inject the jwt", - "type" : "string" - }, - "algo" : { - "description" : "The jwt signing algorithm", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - } - } - }, - "otoroshi.utils.http.DN" : { - "type" : "string", - "description" : "A string representation of a Distinguished Name" - }, - "Any" : { - "oneOf" : [ { - "type" : "object" - }, { - "type" : "array" - }, { - "type" : "string" - }, { - "type" : "boolean" - }, { - "type" : "number" - }, { - "type" : "integer" - } ] - }, - "otoroshi.ssl.ClientAuth" : { - "type" : "string", - "enum" : [ "Need", "None", "Want" ], - "description" : "Client authentication mode" - }, - "otoroshi.models.SimpleOtoroshiAdmin" : { - "description" : "An otoroshi admin user", - "type" : "object", - "properties" : { - "createdAt" : { - "description" : "User creation date", - "type" : "number" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "password" : { - "description" : "User password (bcrypt hashed)", - "type" : "string" - }, - "rights" : { - "description" : "User rights", - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "typ" : { - "description" : "Type of user", - "$ref" : "#/components/schemas/otoroshi.models.OtoroshiAdminType" - }, - "label" : { - "description" : "User label", - "type" : "string" - }, - "type" : { - "description" : "the kind of admin", - "type" : "string", - "enum" : [ "simple", "webauthn" ] - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "username" : { - "description" : "User username", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - } - } - }, - "otoroshi.models.EntityIdentifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptorIdentifier" - }, { - "$ref" : "#/components/schemas/otoroshi.models.ServiceGroupIdentifier" - } ] - }, - "otoroshi.next.plugins.ContextValidation" : { - "description" : "Plugin for context validation", - "type" : "object", - "properties" : { - "validators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "The validators to pass on the current context" - } - } - }, - "otoroshi.plugins.izanami.IzanamiCanaryRoutingConfig" : { - "description" : "Configuration for IzanamiCanary", - "type" : "object", - "properties" : { - "routes" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.plugins.izanami.IzanamiCanaryRoutingConfigRoute" - }, - "description" : "Possible routes" - } - } - }, - "otoroshi.next.plugins.NgApikeyExtractorBasic" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Is it enabled", - "type" : "boolean" - }, - "header_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the header to extract" - }, - "query_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the query param to extract" - } - } - }, - "otoroshi.ssl.pki.models.SignCertResponse" : { - "description" : "Response for a certificate signing operation", - "type" : "object", - "properties" : { - "cert" : { - "description" : "Cert (PEM encoded)", - "type" : "string" - }, - "csr" : { - "description" : "CSR (PEM encoded)", - "type" : "string" - }, - "ca" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string", - "description" : "pem encoded X509 certificate" - } ], - "description" : "Ca cert (PEM encoded)" - } - } - }, - "otoroshi.plugins.discovery.DiscoveryTargetsSelector" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgDomainAndPath" : { - "type" : "string", - "description" : "A string representing a domain and an optional path" - }, - "otoroshi.next.plugins.JQ" : { - "description" : "Plugin to transform body with JQ filters", - "type" : "object", - "properties" : { - "request" : { - "description" : "JQ filter for request", - "type" : "string" - }, - "response" : { - "description" : "JQ filter for response", - "type" : "string" - } - } - }, - "otoroshi.events.KafkaConfig" : { - "description" : "Settings for connection to a kafka cluster", - "type" : "object", - "properties" : { - "hostValidation" : { - "description" : "Enabled TLS hostname validation", - "type" : "boolean" - }, - "servers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "URLs of the kafka servers" - }, - "keyPass" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional keypass" - }, - "mtlsConfig" : { - "description" : "TLS config to access the cluster", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "topic" : { - "description" : "Optional kafka topic (otoroshi-events by default)", - "type" : "string" - }, - "truststore" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional truststore" - }, - "keystore" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional keystore" - }, - "sendEvents" : { - "description" : "Send events to it, or just connect", - "type" : "boolean" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - } - } - }, - "otoroshi.next.plugins.SnowMonkeyChaos" : { - "description" : "Plugin to induce chaos", - "type" : "object", - "properties" : { - "large_request_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLargeRequestFaultConfig" - } ], - "description" : "Config. for large request body faults" - }, - "large_response_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLargeResponseFaultConfig" - } ], - "description" : "Config. for large response faults" - }, - "latency_injection_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLatencyInjectionFaultConfig" - } ], - "description" : "Config. for latency injection faults" - }, - "bad_responses_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgBadResponsesFaultConfig" - } ], - "description" : "Config. for bad responses faults" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesIngressSyncJob" : { - "description" : "Plugin to sync kubernetes ingresses with otoroshi", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.UserRights" : { - "description" : "Represent a list of user rights", - "type" : "object", - "properties" : { - "rights" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.UserRight" - }, - "description" : "Access rights of a user" - } - } - }, - "otoroshi.next.plugins.JsonTransformConfig" : { - "description" : "Configuration for JsonTransform", - "type" : "object", - "properties" : { - "filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter for transformation" - } - } - }, - "otoroshi.plugins.biscuit.vavr_implicits" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.IndexSettingsInterval" : { - "description" : "Elasticseach indexation interval", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jq.JqBodyTransformer" : { - "description" : "Plugin to transform http body using jq filters", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.discovery.DiscoveryJobServiceId" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "id" : { - "description" : "A registration id", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.NgHeaderValuesConfig" : { - "description" : "Configuration for headers plugins", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Value of the headers" - } - } - }, - "otoroshi.next.plugins.wrappers.AccessValidatorWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.MaintenanceMode" : { - "description" : "Plugin for maintainance mode", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "endpoint" : { - "description" : "Kube API endpoint", - "type" : "string" - }, - "templates" : { - "description" : "Templates for created entities", - "type" : "object" - }, - "token" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Kube API access token" - }, - "restartDependantDeployments" : { - "description" : "If enabled, deployments dependant to otoroshi managed secrets (apikeys, certs) will be automatically restarted as secrets are updated", - "type" : "boolean" - }, - "watchGracePeriodSeconds" : { - "format" : "int32", - "description" : "The number of second to wait between receiving a change event and the actual sync", - "type" : "integer" - }, - "crds" : { - "description" : "Enabled crds integration", - "type" : "boolean" - }, - "watch" : { - "description" : "Enabled resources watch", - "type" : "boolean" - }, - "labels" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Kubernetes entities with those labels will be query" - }, - "openshiftDnsOperatorCoreDnsName" : { - "description" : "DNS operator name", - "type" : "string" - }, - "syncIntervalSeconds" : { - "format" : "int64", - "description" : "Number of seconds between syncs", - "type" : "integer" - }, - "kubeDnsOperatorCoreDnsName" : { - "description" : "Kube dns name", - "type" : "string" - }, - "defaultGroup" : { - "description" : "Otoroshi groups where ingress services will be created", - "type" : "string" - }, - "kubeDnsOperatorCoreDnsNamespace" : { - "description" : "Kube dns namespace", - "type" : "string" - }, - "triggerKey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "otoroshiNamespace" : { - "description" : "The namespace where otoroshi is deployed", - "type" : "string" - }, - "watchTimeoutSeconds" : { - "format" : "int32", - "description" : "The timeout to call a watch resources", - "type" : "integer" - }, - "openshiftDnsOperatorCleanupDomains" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Cleanup DNS operator based on domains" - }, - "namespaces" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Kubernetes namespaces that will be query" - }, - "openshiftDnsOperatorCoreDnsPort" : { - "format" : "int32", - "description" : "DNS operator port number", - "type" : "integer" - }, - "coreDnsEnv" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Domain name prefix" - }, - "triggerPath" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "image" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Sidecar image" - }, - "coreDnsConfigMapName" : { - "description" : "The name of the coredns config-map", - "type" : "string" - }, - "clusterDomain" : { - "description" : "The current kubernetes cluster domain", - "type" : "string" - }, - "caCert" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The kubernetes cacert" - }, - "trust" : { - "description" : "Trust Kube CA", - "type" : "boolean" - }, - "ingressClasses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Ingress classes watched by otoroshi ingress controller" - }, - "userPassword" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional username/password to access kube api" - }, - "syncDaikokuApikeysOnly" : { - "description" : "Sync only daikoku apikeys", - "type" : "boolean" - }, - "openshiftDnsOperatorCleanup" : { - "description" : "Cleanup DNS operator", - "type" : "boolean" - }, - "kubeSystemNamespace" : { - "description" : "The namespace containing coredns", - "type" : "string" - }, - "ingressEndpointIp" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "namespacesLabels" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Kubernetes namespaces with those labels that will be query" - }, - "openshiftDnsOperatorCleanupNames" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Cleanup DNS operator based on names" - }, - "kubeDnsOperatorCoreDnsPort" : { - "format" : "int32", - "description" : "Kube dns port number", - "type" : "integer" - }, - "mutatingWebhookName" : { - "description" : "Sidecar webhook name", - "type" : "string" - }, - "kubeLeader" : { - "description" : "Use kubernetes to select a leader", - "type" : "boolean" - }, - "ingressEndpointHostname" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "openshiftDnsOperatorIntegration" : { - "description" : "Enable the openshift operator integration", - "type" : "boolean" - }, - "validatingWebhookName" : { - "description" : "The name of the validating webhook", - "type" : "string" - }, - "coreDnsDeploymentName" : { - "description" : "The name of the coredns deployment", - "type" : "string" - }, - "ingresses" : { - "description" : "Enable ingress controller", - "type" : "boolean" - }, - "useProxyState" : { - "description" : "Use proxy state instead of loading everything from datastore", - "type" : "boolean" - }, - "coreDnsIntegrationDryRun" : { - "description" : "Do not modify coredns config automatically", - "type" : "boolean" - }, - "ingressEndpointPublishedService" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "corednsPort" : { - "format" : "int32", - "description" : "Port of coredns", - "type" : "integer" - }, - "coreDnsIntegration" : { - "description" : "Enable coredns integration", - "type" : "boolean" - }, - "otoroshiServiceName" : { - "description" : "The service name for otoroshi", - "type" : "string" - }, - "meshDomain" : { - "description" : "The domain used for service mesh", - "type" : "string" - }, - "kubeDnsOperatorIntegration" : { - "description" : "Enable the legacy kubedns operator integration", - "type" : "boolean" - }, - "triggerHost" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "--" - }, - "openshiftDnsOperatorCoreDnsNamespace" : { - "description" : "DNS operator namespace", - "type" : "string" - } - } - }, - "otoroshi.script.plugins.Plugins" : { - "description" : "Settings for plugins (of any kind)", - "type" : "object", - "properties" : { - "config" : { - "description" : "Plugins configuration", - "type" : "object" - }, - "enabled" : { - "description" : "Plugins enabled", - "type" : "boolean" - }, - "excluded" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Excluded paths" - }, - "refs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Enabled plugins" - } - } - }, - "otoroshi.plugins.cache.ResponseCacheFilterConfig" : { - "description" : "Configuration for ResponseCache", - "type" : "object", - "properties" : { - "json" : { - "description" : "Config for response cache filter", - "type" : "object" - } - } - }, - "otoroshi.next.models.NgMinimalBackend" : { - "description" : "A backend representation with it's minimal attributes", - "type" : "object", - "properties" : { - "root" : { - "description" : "The root path of the backend or the full rewrite path", - "type" : "string" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - }, - "description" : "The targets of the backend" - }, - "load_balancing" : { - "description" : "Loadbalancing config og the backend", - "$ref" : "#/components/schemas/otoroshi.models.LoadBalancing" - }, - "target_refs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "List of NgStoredBackend ids" - }, - "rewrite" : { - "description" : "Does the backend performs a full url rewrite ?", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.workflow.WorkflowJob" : { - "description" : "Experimental plugin", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.apikeys.ClientCredentialService" : { - "description" : "Plugin that provide the OAuth2 client_credentials flow", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.DisableHttp10" : { - "description" : "Plugin to disable HTTP/1.0", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.loggers.RequestBodyEvent" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "ua" : { - "description" : "The user agent", - "type" : "string" - }, - "reqId" : { - "description" : "The request id", - "type" : "string" - }, - "url" : { - "description" : "The request url", - "type" : "string" - }, - "from" : { - "description" : "The incoming request ip address", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The request headers" - }, - "method" : { - "description" : "The request method", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.StaticBackendConfig" : { - "description" : "???", - "type" : "object", - "properties" : { - "root_path" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.auth.WebAuthnDetails" : { - "description" : "Handle and credentials for a webauthn user", - "type" : "object", - "properties" : { - "handle" : { - "description" : "Webauthn user handle", - "type" : "string" - }, - "credentials" : { - "type" : "object", - "additionalProperties" : { - "type" : "object" - }, - "description" : "Webauthn credentials" - } - } - }, - "otoroshi.tcp.TcpTarget" : { - "description" : "Target for a TCP proxy", - "type" : "object", - "properties" : { - "host" : { - "description" : "Target host", - "type" : "string" - }, - "ip" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Target ip" - }, - "port" : { - "format" : "int32", - "description" : "Target port", - "type" : "integer" - }, - "tls" : { - "description" : "Use tls", - "type" : "boolean" - } - } - }, - "otoroshi.models.GeoPositionRadius" : { - "description" : "Geolocation radius", - "type" : "object", - "properties" : { - "latitude" : { - "format" : "double", - "description" : "Latitude of the position", - "type" : "number" - }, - "longitude" : { - "format" : "double", - "description" : "Longitude of the position", - "type" : "number" - }, - "radius" : { - "format" : "double", - "description" : "Radius of the circle in meters", - "type" : "number" - } - } - }, - "otoroshi.models.InCookie" : { - "description" : "JWT token location (cookie)", - "type" : "object", - "properties" : { - "name" : { - "description" : "Cookie name", - "type" : "string" - }, - "type" : { - "description" : "the kind of location", - "type" : "string", - "enum" : [ "InQueryParam", "InHeader", "InCookie" ] - } - } - }, - "otoroshi.plugins.oidc.OIDCHeaders" : { - "description" : "Plugin to pass OIDC related info as headers", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.apikeys.ApiKeyAllowedOnThisServiceValidator" : { - "description" : "Plugin that validates apikey for specific services", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.RSAlgoSettings" : { - "description" : "Settings to use RSA signing algorithm", - "type" : "object", - "properties" : { - "privateKey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Private key (for signing)" - }, - "size" : { - "format" : "int32", - "description" : "SHA function size", - "type" : "integer" - }, - "publicKey" : { - "description" : "Public key (for verification)", - "type" : "string" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.tcp.TcpService" : { - "description" : "Model for a TCP proxy", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Service enabled", - "type" : "boolean" - }, - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "port" : { - "format" : "int32", - "description" : "network port", - "type" : "integer" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "rules" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.tcp.TcpRule" - }, - "description" : "Routing rules" - }, - "clientAuth" : { - "description" : "Use client authentication", - "$ref" : "#/components/schemas/otoroshi.ssl.ClientAuth" - }, - "interface" : { - "description" : "Network interface", - "type" : "string" - }, - "sni" : { - "description" : "SNI settings", - "$ref" : "#/components/schemas/otoroshi.tcp.SniSettings" - }, - "id" : { - "description" : "Entity id", - "type" : "string" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "tls" : { - "description" : "TLS mode", - "$ref" : "#/components/schemas/otoroshi.tcp.TlsMode" - } - } - }, - "otoroshi.next.plugins.TooComplexQueryError" : { - "description" : "???", - "type" : "object", - "properties" : { } - }, - "WebAuthnRegistrationFinishBody" : { - "type" : "object", - "description" : "" - }, - "otoroshi.models.LocalJwtVerifier" : { - "description" : "Local jwt verifier (deprecated)", - "type" : "object", - "properties" : { - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Verifier excluded paths" - }, - "algoSettings" : { - "description" : "Algo settings", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "source" : { - "description" : "Token source", - "$ref" : "#/components/schemas/otoroshi.models.JwtTokenLocation" - }, - "type" : { - "description" : "the kind of verifier", - "type" : "string", - "enum" : [ "global", "local", "ref" ] - }, - "strict" : { - "description" : "Strict token verification", - "type" : "boolean" - }, - "strategy" : { - "description" : "Token strategy", - "$ref" : "#/components/schemas/otoroshi.models.VerifierStrategy" - }, - "enabled" : { - "description" : "Verifier enabled", - "type" : "boolean" - } - } - }, - "otoroshi.utils.gzip.GzipConfig" : { - "description" : "Settings for gzip support", - "type" : "object", - "properties" : { - "compressionLevel" : { - "format" : "int32", - "description" : "Compression level (0 - 9)", - "type" : "integer" - }, - "blackList" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "blocklisted content types" - }, - "chunkedThreshold" : { - "format" : "int32", - "description" : "Chunk size", - "type" : "integer" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Excluded paths" - }, - "bufferSize" : { - "format" : "int32", - "description" : "Buffer size in bytes", - "type" : "integer" - }, - "whiteList" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "allow listed content types" - }, - "enabled" : { - "description" : "Gzip enabled", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.useragent.UserAgentExtractor" : { - "description" : "Plugin that extract user-agent related infos", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.Webhook" : { - "description" : "Settings for webhook call", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers to authorize the call or whatever" - }, - "mtlsConfig" : { - "description" : "TLS config when calling webhook", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "url" : { - "description" : "The URL where events are posted", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgCustomTimeouts" : { - "description" : "Custom timeouts per path", - "type" : "object", - "properties" : { - "connection_timeout" : { - "format" : "int64", - "description" : "Timeout at connection", - "type" : "integer" - }, - "call_and_stream_timeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (hard timeout, connection will be closed after that duration)", - "type" : "integer" - }, - "path" : { - "description" : "path on which this configuration works", - "type" : "string" - }, - "call_timeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (soft timeout as it's enforced by the circuit breaker)", - "type" : "integer" - }, - "idle_timeout" : { - "format" : "int64", - "description" : "Timeout on idle connection", - "type" : "integer" - }, - "global_timeout" : { - "format" : "int64", - "description" : "Specify how long the global call (with retries) should last at most in milliseconds", - "type" : "integer" - } - } - }, - "otoroshi.models.VerifierStrategy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.DefaultToken" - }, { - "$ref" : "#/components/schemas/otoroshi.models.PassThrough" - }, { - "$ref" : "#/components/schemas/otoroshi.models.Sign" - }, { - "$ref" : "#/components/schemas/otoroshi.models.Transform" - } ] - }, - "otoroshi.next.plugins.TcpTunnel" : { - "description" : "Plugin to have tcp tunnels over websockets", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.DefaultToken" : { - "description" : "Default jwt token when no other token validated", - "type" : "object", - "properties" : { - "verificationSettings" : { - "description" : "Verification settings", - "$ref" : "#/components/schemas/otoroshi.models.VerificationSettings" - }, - "type" : { - "description" : "the kind of strategy", - "type" : "string", - "enum" : [ "PassThrough", "Sign", "Transform", "DefaultToken" ] - }, - "strict" : { - "description" : "If the token already exists in the request, then fail", - "type" : "boolean" - }, - "token" : { - "description" : "The default token", - "type" : "object" - } - } - }, - "otoroshi.models.RemainingQuotas" : { - "description" : "Remaining quotas for an apikey", - "type" : "object", - "properties" : { - "currentCallsPerSec" : { - "format" : "int64", - "description" : "Current number of call per second", - "type" : "integer" - }, - "remainingCallsPerSec" : { - "format" : "int64", - "description" : "Remaining number of call per second", - "type" : "integer" - }, - "currentCallsPerDay" : { - "format" : "int64", - "description" : "Current number of call per day", - "type" : "integer" - }, - "authorizedCallsPerDay" : { - "format" : "int64", - "description" : "Number of authorized call per day", - "type" : "integer" - }, - "currentCallsPerMonth" : { - "format" : "int64", - "description" : "Current number of call per month", - "type" : "integer" - }, - "remainingCallsPerMonth" : { - "format" : "int64", - "description" : "Remaining number of call per month", - "type" : "integer" - }, - "authorizedCallsPerSec" : { - "format" : "int64", - "description" : "Number of authorized call per second", - "type" : "integer" - }, - "authorizedCallsPerMonth" : { - "format" : "int64", - "description" : "Number of authorized call per month", - "type" : "integer" - }, - "remainingCallsPerDay" : { - "format" : "int64", - "description" : "Remaining number of call per day", - "type" : "integer" - } - } - }, - "otoroshi.models.GlobalScripts" : { - "description" : "Settings to apply plugins globally", - "type" : "object", - "properties" : { - "jobConfig" : { - "description" : "jobs enabled", - "type" : "object" - }, - "enabled" : { - "description" : "Global scripts enabled", - "type" : "boolean" - }, - "transformersConfig" : { - "description" : "transformers config", - "type" : "object" - }, - "transformersRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "transformers enabled" - }, - "preRouteRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "pre-route plugins enabled" - }, - "sinkConfig" : { - "description" : "sinks config", - "type" : "object" - }, - "jobRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "running jobs" - }, - "validatorRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "validator enabled" - }, - "sinkRefs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "sinks enabled" - }, - "preRouteConfig" : { - "description" : "pre-route config", - "type" : "object" - }, - "validatorConfig" : { - "description" : "validator config", - "type" : "object" - } - } - }, - "ErrorResponse" : { - "type" : "object", - "description" : "Typical error returned by otoroshi", - "properties" : { - "error" : { - "type" : "string", - "description" : "the error name" - }, - "error_description" : { - "type" : "string", - "description" : "A short description of the error if one" - }, - "Otoroshi-Error" : { - "type" : "string", - "description" : "sometimes, the error name is here" - }, - "Otoroshi-Error-Msg" : { - "type" : "string", - "description" : "sometimes, the error description is here" - } - } - }, - "otoroshi.plugins.cache.ResponseCacheConfig" : { - "description" : "Configuration for ResponseCache", - "type" : "object", - "properties" : { - "json" : { - "description" : "Config for response cache", - "type" : "object" - } - } - }, - "otoroshi.next.models.GraphQLFormats" : { - "description" : "???", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.biscuit.BiscuitValidator" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.JwtAuthConstraints" : { - "description" : "Settings to extract apikey from a jwt token", - "type" : "object", - "properties" : { - "keyPairSigned" : { - "description" : "The jwt token is signed by a keypair from a cert found from its id in apikey meta. 'jwt-sign-keypair'", - "type" : "boolean" - }, - "cookieName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Cookie name to extract jwt token" - }, - "queryName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Query param name to extract jwt token" - }, - "headerName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to extract jwt token" - }, - "secretSigned" : { - "description" : "Jwt token signed with the client_secret", - "type" : "boolean" - }, - "maxJwtLifespanSecs" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "integer", - "format" : "int64" - } ], - "description" : "Check if token does not have a long lifespan" - }, - "enabled" : { - "description" : "Constraint enabled", - "type" : "boolean" - }, - "includeRequestAttributes" : { - "description" : "Jwt token should include verb and path", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.apikeys.ClientCredentialFlowExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.log4j.Log4ShellFilter" : { - "description" : "Plugin to mitigate Log4Shell attacks", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.StoredNgBackend" : { - "description" : "A backend that can be stored in the otoroshi datastore", - "type" : "object", - "properties" : { - "description" : { - "description" : "The description of the backend", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The tags of the backend" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The metadata of the backend" - }, - "backend" : { - "description" : "The actual backend", - "$ref" : "#/components/schemas/otoroshi.next.models.NgBackend" - }, - "name" : { - "description" : "The name of the backend", - "type" : "string" - }, - "_loc" : { - "description" : "The location of the backend", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "id" : { - "description" : "The id of the backend", - "type" : "string" - } - } - }, - "Empty" : { - "type" : "object", - "description" : "an empty body. Useful for RPC like endpoints" - }, - "otoroshi.models.ServiceGroupIdentifier" : { - "type" : "string", - "description" : "the id of a group prefixed by 'group_'" - }, - "otoroshi.script.AccessValidatorRef" : { - "description" : "References to access validation plugins", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Access validator plugins enabled", - "type" : "boolean" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Excluded paths" - }, - "refs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Enabled plugins" - }, - "config" : { - "description" : "Access validator plugins configuration", - "type" : "object" - } - } - }, - "otoroshi.ssl.pki.models.GenCertResponse" : { - "description" : "Response for a certificate generation operation", - "type" : "object", - "properties" : { - "ca" : { - "description" : "Ca cert (PEM encoded)", - "type" : "string" - }, - "caChain" : { - "type" : "array", - "items" : { - "type" : "string", - "description" : "pem encoded X509 certificate" - }, - "description" : "Ca chain (PEM encoded)" - }, - "csrQuery" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.ssl.pki.models.GenCsrQuery" - } ], - "description" : "JSON generation query" - }, - "cert" : { - "description" : "Cert (PEM encoded)", - "type" : "string" - }, - "serial" : { - "format" : "int64", - "description" : "Certificate serial number", - "type" : "integer" - }, - "key" : { - "description" : "Private key (PEM encoded)", - "type" : "string" - }, - "csr" : { - "description" : "CSR (PEM encoded)", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgPluginInstanceConfig" : { - "description" : "The current configuration for a plugin", - "type" : "object" - }, - "otoroshi.models.PrivateAppsUser" : { - "description" : "User session for private apps", - "type" : "object", - "properties" : { - "realm" : { - "description" : "Session realm name", - "type" : "string" - }, - "token" : { - "description" : "Session tokens (from OAuth)", - "type" : "object" - }, - "expiredAt" : { - "description" : "Session expiration date", - "type" : "number" - }, - "profile" : { - "description" : "Session user profile", - "type" : "object" - }, - "lastRefresh" : { - "description" : "Session last refresh (if OAuth refresh_token supported)", - "type" : "number" - }, - "randomId" : { - "description" : "Session random id", - "type" : "string" - }, - "email" : { - "description" : "Session user email", - "type" : "string" - }, - "createdAt" : { - "description" : "Creation date of the session", - "type" : "number" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "authConfigId" : { - "description" : "Auth module id that created the session", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "otoroshiData" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "object" - } ], - "description" : "Otoroshi oriented metadata" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - } - } - }, - "otoroshi.plugins.geoloc.GeolocationInfoEndpoint" : { - "description" : "Plugin that send geolocation infos to the client through an endpoint", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgTreeNodePath" : { - "description" : "A node of the tree router", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.QueryTransformer" : { - "description" : "Plugin to transform query string", - "type" : "object", - "properties" : { - "remove" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Remove query params" - }, - "rename" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Rename query params to" - } - } - }, - "HostMetrics" : { - "type" : "object", - "description" : "Host metrics" - }, - "otoroshi.next.models.NgService" : { - "description" : "A composition of multiple routes with the same plugins", - "type" : "object", - "properties" : { - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The metadata of the service" - }, - "client" : { - "description" : "The client config of the service", - "$ref" : "#/components/schemas/otoroshi.next.models.NgClientConfig" - }, - "name" : { - "description" : "The name of the service", - "type" : "string" - }, - "id" : { - "description" : "The id of the service", - "type" : "string" - }, - "capture" : { - "description" : "Capture http traffic", - "type" : "boolean" - }, - "description" : { - "description" : "The description of the service", - "type" : "string" - }, - "routes" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgMinimalRoute" - }, - "description" : "The routes of the service" - }, - "debug_flow" : { - "description" : "Enable report debugging", - "type" : "boolean" - }, - "export_reporting" : { - "description" : "Export the execution reporting through standard data exporter", - "type" : "boolean" - }, - "_loc" : { - "description" : "The location of the service", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "enabled" : { - "description" : "Is the service enabled", - "type" : "boolean" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The tags of the service" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The groups of the service" - } - } - }, - "AlertEventList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.events.AlertEvent" - } - }, - "otoroshi.models.HealthCheck" : { - "description" : "Healthcheck settings for a service", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Whether or not healthcheck is enabled on the current service descriptor", - "type" : "boolean" - }, - "url" : { - "description" : "The URL to check", - "type" : "string" - } - } - }, - "otoroshi.plugins.core.apikeys.ClientIdApikeyExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.StaticResponseConfig" : { - "description" : "Configuration for StaticResponse", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "Status of the response", - "type" : "integer" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers of the response" - }, - "body" : { - "description" : "Body of the response", - "type" : "string" - } - } - }, - "otoroshi.plugins.useragent.UserAgentInfoHeader" : { - "description" : "Plugin that pass user-agent infos in headers", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.HeadersValidation" : { - "description" : "Plugin to validate headers", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The headers value being checked" - } - } - }, - "otoroshi.models.SnowMonkeyConfig" : { - "description" : "Settings for the snow monkey (chaos engineering)", - "type" : "object", - "properties" : { - "dryRun" : { - "description" : "Whether or not outages will actualy impact requests", - "type" : "boolean" - }, - "outageDurationTo" : { - "description" : "End of outage duration range", - "type" : "number" - }, - "chaosConfig" : { - "description" : "Chaos settings", - "$ref" : "#/components/schemas/otoroshi.models.ChaosConfig" - }, - "timesPerDay" : { - "format" : "int32", - "description" : "Number of time per day each service will be outage", - "type" : "integer" - }, - "outageDurationFrom" : { - "description" : "Start of outage duration range", - "type" : "number" - }, - "startTime" : { - "description" : "Start time of Snow Monkey each day", - "type" : "string" - }, - "includeUserFacingDescriptors" : { - "description" : "Whether or not user facing apps. will be impacted by Snow Monkey", - "type" : "boolean" - }, - "targetGroups" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Groups impacted by Snow Monkey. If empty, all groups will be impacted" - }, - "enabled" : { - "description" : "Whether or not this config is enabled", - "type" : "boolean" - }, - "stopTime" : { - "description" : "Stop time of Snow Monkey each day", - "type" : "string" - }, - "outageStrategy" : { - "description" : "", - "$ref" : "#/components/schemas/otoroshi.models.OutageStrategy" - } - } - }, - "otoroshi.models.IndexSettings" : { - "description" : "Elasticseach indexation settings", - "type" : "object", - "properties" : { - "clientSide" : { - "description" : "Enable index splitting on client side", - "type" : "boolean" - }, - "interval" : { - "description" : "Index splitting interval", - "$ref" : "#/components/schemas/otoroshi.models.IndexSettingsInterval" - } - } - }, - "otoroshi.auth.NameIDFormat" : { - "description" : "The name ID Format to use for the subject", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.GraphQLQuery" : { - "description" : "???", - "type" : "object", - "properties" : { - "response_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "url" : { - "description" : "???", - "type" : "string" - }, - "response_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "???" - }, - "timeout" : { - "format" : "int64", - "description" : "???", - "type" : "integer" - }, - "query" : { - "description" : "???", - "type" : "string" - }, - "method" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.models.ZoneMatch" : { - "description" : "Match a target if in the same zone", - "type" : "object", - "properties" : { - "zone" : { - "description" : "Zone name", - "type" : "string" - }, - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - } - } - }, - "otoroshi.next.models.NgPlugins" : { - "description" : "A set of NgPluginInstance", - "type" : "object", - "properties" : { - "slots" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgPluginInstance" - }, - "description" : "All the NgPluginInstance" - } - } - }, - "otoroshi.next.plugins.Http2Caller" : { - "description" : "Experimental plugin", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob" : { - "description" : "Plugin to import entities from kubernetes CRDs", - "type" : "object", - "properties" : { } - }, - "otoroshi.auth.GroupFilter" : { - "description" : "Filter for a LDAP group", - "type" : "object", - "properties" : { - "group" : { - "description" : "The LDAP group", - "type" : "string" - }, - "tenant" : { - "description" : "The tenant associated with this group", - "$ref" : "#/components/schemas/otoroshi.models.TenantAccess" - }, - "team" : { - "description" : "The team associated with this group", - "type" : "string" - } - } - }, - "otoroshi.plugins.mirror.RequestContext" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "descriptor" : { - "description" : "Current descriptor", - "$ref" : "#/components/schemas/otoroshi.models.ServiceDescriptor" - }, - "id" : { - "description" : "The id of the request", - "type" : "string" - }, - "config" : { - "description" : "Current plugin config", - "$ref" : "#/components/schemas/otoroshi.plugins.mirror.MirroringPluginConfig" - } - } - }, - "otoroshi.plugins.biscuit.PreRoutingVerifierContext" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "ctx" : { - "description" : "Current context", - "$ref" : "#/components/schemas/otoroshi.script.PreRoutingContext" - }, - "apk" : { - "description" : "Current apikey", - "$ref" : "#/components/schemas/otoroshi.models.ApiKey" - } - } - }, - "CodeBody" : { - "type" : "string", - "description" : "Plugin scala code" - }, - "otoroshi.models.AutoCert" : { - "description" : "Settings to generate certificates on the fly", - "type" : "object", - "properties" : { - "allowed" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "allowed domains" - }, - "enabled" : { - "description" : "Enable auto cert", - "type" : "boolean" - }, - "replyNicely" : { - "description" : "Reply TLS error with an auto generated certificate for the domain", - "type" : "boolean" - }, - "notAllowed" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "not allowed domains" - }, - "caRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Generate cert from the following CA" - } - } - }, - "CertValidResponse" : { - "type" : "object", - "description" : "Is certificate valid", - "properties" : { - "valid" : { - "type" : "boolean" - } - } - }, - "otoroshi.models.RestrictionPath" : { - "description" : "Represent an http request on which restrictions will apply", - "type" : "object", - "properties" : { - "method" : { - "description" : "Method of the http request", - "type" : "string" - }, - "path" : { - "description" : "Path of the http request", - "type" : "string" - } - } - }, - "otoroshi.plugins.loggers.BodyLoggerFilterConfig" : { - "description" : "Configuration for BodyLogger", - "type" : "object", - "properties" : { - "json" : { - "description" : "The current config", - "type" : "object" - } - } - }, - "otoroshi.plugins.external.ExternalHttpValidator" : { - "description" : "Plugin that validates call based on an external http service", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgClientConfig" : { - "description" : "Settings for the http client when http request is forwarded", - "type" : "object", - "properties" : { - "idle_timeout" : { - "format" : "int64", - "description" : "Timeout on idle connection", - "type" : "integer" - }, - "sample_interval" : { - "format" : "int64", - "description" : "Specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted", - "type" : "integer" - }, - "cache_connection_settings" : { - "description" : "Cached connection settings", - "$ref" : "#/components/schemas/otoroshi.next.models.NgCacheConnectionSettings" - }, - "call_and_stream_timeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (hard timeout, connection will be closed after that duration)", - "type" : "integer" - }, - "custom_timeouts" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgCustomTimeouts" - }, - "description" : "Custom timeouts per path" - }, - "connection_timeout" : { - "format" : "int64", - "description" : "Timeout at connection", - "type" : "integer" - }, - "call_timeout" : { - "format" : "int64", - "description" : "Specify how long each call should last at most in milliseconds (soft timeout as it's enforced by the circuit breaker)", - "type" : "integer" - }, - "global_timeout" : { - "format" : "int64", - "description" : "Specify how long the global call (with retries) should last at most in milliseconds", - "type" : "integer" - }, - "retry_initial_delay" : { - "format" : "int64", - "description" : "Specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor", - "type" : "integer" - }, - "backoff_factor" : { - "format" : "int64", - "description" : "Specify the factor to multiply the delay for each retry", - "type" : "integer" - }, - "proxy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy settings for http client" - }, - "retries" : { - "format" : "int32", - "description" : "Specify how many times the client will try to fetch the result of the request after an error before giving up.", - "type" : "integer" - }, - "max_errors" : { - "format" : "int32", - "description" : "Specify how many errors can pass before opening the circuit breaker", - "type" : "integer" - } - } - }, - "otoroshi.plugins.composite.CompositePlugin" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.wrappers.CompositeWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.GeolocationMatch" : { - "description" : "Match a target if in the same geo location radius", - "type" : "object", - "properties" : { - "positions" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.GeoPositionRadius" - }, - "description" : "Possible positions" - }, - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - } - } - }, - "BulkResponseBody" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "string", - "description" : "the id of the entity" - }, - "status" : { - "type" : "integer", - "description" : "operation status" - }, - "error" : { - "type" : "string", - "description" : "the error of the operation if one" - } - }, - "required" : [ "uid", "status" ] - } - }, - "otoroshi.models.BadResponsesFaultConfig" : { - "description" : "List of bad response settings", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0", - "type" : "number" - }, - "responses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.BadResponse" - }, - "description" : "The possibles responses" - } - } - }, - "otoroshi.next.plugins.SOAPActionConfig" : { - "description" : "Configuration for SOAPAction", - "type" : "object", - "properties" : { - "jq_response_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform response body" - }, - "jq_request_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform request body" - }, - "preserve_query" : { - "description" : "Preserve query params", - "type" : "boolean" - }, - "convert_request_body_to_xml" : { - "description" : "Convert json body to xml", - "type" : "boolean" - }, - "charset" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The body charset" - }, - "url" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "SOAP endpoint" - }, - "action" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The soap action if one" - }, - "envelope" : { - "description" : "The soap envelope to call", - "type" : "string" - } - } - }, - "otoroshi.models.Target" : { - "description" : "A target model for a service (destination for forwarded requests)", - "type" : "object", - "properties" : { - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Tags for this target" - }, - "host" : { - "description" : "The host on which the HTTP call will be forwarded. Can be a domain name, or an IP address. Can also have a port", - "type" : "string" - }, - "weight" : { - "format" : "int32", - "description" : "The weight of the target when choosing", - "type" : "integer" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata for this target" - }, - "protocol" : { - "description" : "Protocol for the target", - "type" : "string", - "enum" : [ "HTTP/1.0", "HTTP/1.1", "HTTP/2.0" ] - }, - "predicate" : { - "description" : "Predicate to choose this target", - "$ref" : "#/components/schemas/otoroshi.models.TargetPredicate" - }, - "ipAddress" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Target ip address. Usefull to make manual DNS resolution without breaking SNI" - }, - "mtlsConfig" : { - "description" : "TLS settings to contact this target", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "scheme" : { - "description" : "The protocol used for communication. Can be http or https", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.Redirection" : { - "description" : "Plugin to perform redirections", - "type" : "object", - "properties" : { - "code" : { - "format" : "int32", - "description" : "Redirection status code used", - "type" : "integer" - }, - "to" : { - "description" : "The redirection url", - "type" : "string" - } - } - }, - "otoroshi.plugins.discovery.DiscoveryJobRegistrationId" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "id" : { - "description" : "A service id", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.ContextValidationConfig" : { - "description" : "Configuration for ContextValidation", - "type" : "object", - "properties" : { - "validators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "The validators to pass on the current context" - } - } - }, - "SimpleAdminList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - } - }, - "otoroshi.models.Proxies" : { - "description" : "Various web proxy settings for http client", - "type" : "object", - "properties" : { - "elastic" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to call elastic" - }, - "eventsWebhooks" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to call webhooks" - }, - "jwk" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to fetch jwks" - }, - "auth" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to call OAuth providers" - }, - "clevercloud" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to call clevercloud" - }, - "alertEmails" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to send alert emails" - }, - "authority" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to check authorities" - }, - "services" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy used to access services targets" - } - } - }, - "otoroshi.next.plugins.GlobalThrottling" : { - "description" : "Plugin for throttling", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.ApiKeyRotation" : { - "description" : "Settings for automatic apikey rotation with grace period", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Rotation enabled", - "type" : "boolean" - }, - "rotationEvery" : { - "format" : "int64", - "description" : "Rotate every n hours", - "type" : "integer" - }, - "gracePeriod" : { - "format" : "int64", - "description" : "period (in hours) during which both secrets works", - "type" : "integer" - }, - "nextSecret" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Next client_secret value" - } - } - }, - "otoroshi.utils.http.CacheConnectionSettings" : { - "description" : "The settings for http cached connection at host level", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Enable Cached connections at host tevel", - "type" : "boolean" - }, - "queueSize" : { - "format" : "int32", - "description" : "The size for the request queue", - "type" : "integer" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.tcp.SniSettings" : { - "description" : "SNI settings for a TCP proxy", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "SNI extraction enabled", - "type" : "boolean" - }, - "forwardIfNoMatch" : { - "description" : "", - "type" : "boolean" - }, - "forwardsTo" : { - "description" : "forwards call to", - "$ref" : "#/components/schemas/otoroshi.tcp.TcpTarget" - } - } - }, - "otoroshi.plugins.clientcert.HasClientCertMatchingValidator" : { - "description" : "Plugin that validates client certificates", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.PluginIndex" : { - "description" : "Custom index for plugins", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.LoadBalancing" : { - "type" : "object", - "description" : "Loadbalancing strategy", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "BestResponseTime", "IpAddressHash", "Random", "RoundRobin", "Sticky", "WeightedBestResponseTime" ] - }, - "ratio" : { - "type" : "number", - "format" : "double" - } - } - }, - "otoroshi.models.RedirectionSettings" : { - "description" : "Settings for routing redirection", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Whether or not redirection is enabled", - "type" : "boolean" - }, - "code" : { - "format" : "int32", - "description" : "The http redirect code", - "type" : "integer" - }, - "to" : { - "description" : "The location for redirection", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.NgOtoroshiChallengeKeys" : { - "description" : "Configuration for OtoroshiChallenge", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.wrappers.RequestTransformerWrapper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.OtoroshiAdmin" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.SimpleOtoroshiAdmin" - }, { - "$ref" : "#/components/schemas/otoroshi.models.WebAuthnOtoroshiAdmin" - } ] - }, - "otoroshi.models.JwtVerifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.GlobalJwtVerifier" - }, { - "$ref" : "#/components/schemas/otoroshi.models.LocalJwtVerifier" - }, { - "$ref" : "#/components/schemas/otoroshi.models.RefJwtVerifier" - } ] - }, - "otoroshi.next.plugins.MockFormData" : { - "description" : "???", - "type" : "object", - "properties" : { - "resources" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockResource" - }, - "description" : "???" - }, - "endpoints" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.MockEndpoint" - }, - "description" : "???" - } - } - }, - "otoroshi.plugins.jsoup.HtmlPatcher" : { - "description" : "Plugin to transform html response body", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.apikeys.ClientCredentialFlowBody" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "scope" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Scope of the request" - }, - "clientId" : { - "description" : "The request client id", - "type" : "string" - }, - "clientSecret" : { - "description" : "The request client secret", - "type" : "string" - }, - "grantType" : { - "description" : "The grand type (client_credentials)", - "type" : "string" - }, - "bearerKind" : { - "description" : "The kind of bearer", - "type" : "string" - } - } - }, - "otoroshi.auth.BasicAuthModuleConfig" : { - "description" : "Authentication module that let you use otoroshi as the identity provider", - "type" : "object", - "properties" : { - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "metadata of the module" - }, - "sessionCookieValues" : { - "description" : "Settings for the session cookie", - "$ref" : "#/components/schemas/otoroshi.auth.SessionCookieValues" - }, - "basicAuth" : { - "description" : "Use standard basic auth or web login form", - "type" : "boolean" - }, - "type" : { - "description" : "the type of the module", - "type" : "string", - "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] - }, - "userValidators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "Validators that will check if the current user is authorized after successful login" - }, - "_loc" : { - "description" : "location of the module", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "users" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.auth.BasicAuthUser" - }, - "description" : "Users attached to the module" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "sessionMaxAge" : { - "format" : "int32", - "description" : "max age for the session cookie in seconds", - "type" : "integer" - }, - "name" : { - "description" : "name of the module", - "type" : "string" - }, - "webauthn" : { - "description" : "Use webauthn for login", - "type" : "boolean" - }, - "clientSideSessionEnabled" : { - "description" : "???", - "type" : "boolean" - }, - "id" : { - "description" : "id of the module", - "type" : "string" - }, - "desc" : { - "description" : "description of the module", - "type" : "string" - } - } - }, - "otoroshi.plugins.metrics.PrometheusSupport" : { - "description" : "Plugin to collect service metrics", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.izanami.IzanamiProxyConfig" : { - "description" : "Configuration for IzanamiProxy", - "type" : "object", - "properties" : { - "izanamiClientId" : { - "description" : "Izanami client id", - "type" : "string" - }, - "path" : { - "description" : "Izanami server path", - "type" : "string" - }, - "mtls" : { - "description" : "Izanami server tls config", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "featuresEnabled" : { - "description" : "Is features proxy enabled", - "type" : "boolean" - }, - "featuresWithContextEnabled" : { - "description" : "Is contextual features enabled ?", - "type" : "boolean" - }, - "izanamiClientSecret" : { - "description" : "Izanami client secret", - "type" : "string" - }, - "timeout" : { - "description" : "Timeout when talking to the izanami server", - "type" : "number" - }, - "configurationEnabled" : { - "description" : "Is configuration proxy enabled", - "type" : "boolean" - }, - "featurePattern" : { - "description" : "the searched pattern for features", - "type" : "string" - }, - "izanamiUrl" : { - "description" : "Izanami server url", - "type" : "string" - }, - "autoContext" : { - "description" : "Automatically pass the current user and/or apikey as context", - "type" : "boolean" - }, - "configPattern" : { - "description" : "the searched pattern for config", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.NgBadResponsesFaultConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "bad response ratio", - "type" : "number" - }, - "responses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgBadResponse" - }, - "description" : "possible response" - } - } - }, - "otoroshi.plugins.accesslog.KafkaAccessLog" : { - "description" : "Plugin that log access in a kafka topic", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.AdditionalHeadersOut" : { - "description" : "Plugin that add headers on a response", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The headers added to the response" - } - } - }, - "otoroshi.plugins.core.apikeys.CustomHeadersApikeyExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.utils.mailer.EmailLocation" : { - "description" : "Email location settings", - "type" : "object", - "properties" : { - "name" : { - "description" : "Destination name", - "type" : "string" - }, - "email" : { - "description" : "Email address", - "type" : "string" - } - } - }, - "otoroshi.plugins.envoy.EnvoyControlPlane" : { - "description" : "Experimental plugin", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.RackMatch" : { - "description" : "Match a target if in the same rack", - "type" : "object", - "properties" : { - "rack" : { - "description" : "Rack name", - "type" : "string" - }, - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - } - } - }, - "otoroshi.plugins.oidc.ThirdPartyApiKeyConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.ESAlgoSettings" : { - "description" : "Settings to use elliptic curve signing algorithm", - "type" : "object", - "properties" : { - "privateKey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The EC private key. If used for verification, can be null" - }, - "size" : { - "format" : "int32", - "description" : "SHA function size", - "type" : "integer" - }, - "publicKey" : { - "description" : "The EC private key. If used for signing, can be null", - "type" : "string" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.plugins.oidc.OIDCThirdPartyApiKeyConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "deprecated" - }, - "headerName" : { - "description" : "deprecated", - "type" : "string" - }, - "localVerificationOnly" : { - "description" : "deprecated", - "type" : "boolean" - }, - "enabled" : { - "description" : "deprecated", - "type" : "boolean" - }, - "ttl" : { - "format" : "int64", - "description" : "deprecated", - "type" : "integer" - }, - "uniqueApiKey" : { - "description" : "deprecated", - "type" : "boolean" - }, - "rolesPath" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "deprecated" - }, - "mode" : { - "description" : "deprecated", - "$ref" : "#/components/schemas/otoroshi.plugins.oidc.OIDCThirdPartyApiKeyConfigMode" - }, - "quotasEnabled" : { - "description" : "deprecated", - "type" : "boolean" - }, - "monthlyQuota" : { - "format" : "int64", - "description" : "deprecated", - "type" : "integer" - }, - "scopes" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "deprecated" - }, - "roles" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "deprecated" - }, - "throttlingQuota" : { - "format" : "int64", - "description" : "deprecated", - "type" : "integer" - }, - "dailyQuota" : { - "format" : "int64", - "description" : "deprecated", - "type" : "integer" - }, - "oidcConfigRef" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "deprecated" - } - } - }, - "otoroshi.plugins.geoloc.GeolocationInfoHeader" : { - "description" : "Plugin that send geolocation infos to the backend through a header", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.NoneGeolocationSettings" : { - "type" : "object", - "description" : "No geolocation extraction", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "none" ] - } - } - }, - "otoroshi.next.plugins.GraphQLProxy" : { - "description" : "???", - "type" : "object", - "properties" : { - "max_complexity" : { - "format" : "double", - "description" : "???", - "type" : "number" - }, - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "???" - }, - "path" : { - "description" : "???", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "???" - }, - "endpoint" : { - "description" : "???", - "type" : "string" - }, - "max_depth" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - } - } - }, - "otoroshi.next.models.NgServiceDataStore" : { - "description" : "The datastore for services", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.models.NgPluginInstance" : { - "description" : "The current configuration and target for a plugin", - "type" : "object", - "properties" : { - "debug" : { - "description" : "Is the plugin in debug mode", - "type" : "boolean" - }, - "config" : { - "description" : "The config. of the plugin", - "type" : "object" - }, - "exclude" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Excluded paths" - }, - "plugin_index" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.models.PluginIndex" - } ], - "description" : "Custom index for plugins" - }, - "include" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Included paths" - }, - "plugin" : { - "description" : "The id of the plugin", - "type" : "string" - }, - "enabled" : { - "description" : "Is the plugin enabled", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.JQRequestConfig" : { - "description" : "Configuration for JQRequest", - "type" : "object", - "properties" : { - "filter" : { - "description" : "JQ filter for request", - "type" : "string" - } - } - }, - "otoroshi.plugins.hmac.HMACValidator" : { - "description" : "Plugin that can validate an hmac call", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgRestrictions" : { - "description" : "Plugin to apply routing restrictions", - "type" : "object", - "properties" : { - "allow_last" : { - "description" : "Evaluates allowed paths after forbidden and not found", - "type" : "boolean" - }, - "allowed" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Allowed paths" - }, - "forbidden" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Forbidden paths" - }, - "not_found" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Not found paths" - } - } - }, - "WebAuthnRegistrationStartBody" : { - "type" : "object", - "description" : "" - }, - "PatchDocument" : { - "type" : "object", - "description" : "A JSONPatch document as defined by RFC 6902", - "required" : [ "op", "path" ], - "properties" : { - "op" : { - "type" : "string", - "description" : "The operation to be performed", - "enum" : [ "add", "remove", "replace", "move", "copy", "test" ] - }, - "path" : { - "type" : "string", - "description" : "A JSON-Pointer" - }, - "value" : { - "type" : "object", - "description" : "The value to be used within the operations." - }, - "from" : { - "type" : "string", - "description" : "A string containing a JSON Pointer value." - } - } - }, - "otoroshi.next.plugins.SendOtoroshiHeadersBack" : { - "description" : "Plugin to enrich response header with otoroshi infos", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.accesslog.AccessLogJson" : { - "description" : "Plugin that log access in json", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.Tenant" : { - "description" : "An otoroshi model for an organization (otoroshi-ui)", - "type" : "object", - "properties" : { - "description" : { - "description" : "Entity description", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "id" : { - "description" : "Entity id", - "$ref" : "#/components/schemas/otoroshi.models.TenantId" - } - } - }, - "otoroshi.models.BackOfficeUser" : { - "description" : "User session for otoroshi-ui admins", - "type" : "object", - "properties" : { - "randomId" : { - "description" : "Session user random id", - "type" : "string" - }, - "profile" : { - "description" : "Session user profile", - "type" : "object" - }, - "authConfigId" : { - "description" : "Session created from auth module id", - "type" : "string" - }, - "rights" : { - "description" : "Session user rights", - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "createdAt" : { - "description" : "Creation date for the session", - "type" : "number" - }, - "token" : { - "description" : "Session tokens (only if OAuth/OIDC)", - "type" : "object" - }, - "name" : { - "description" : "Session user name", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "email" : { - "description" : "User email", - "type" : "string" - }, - "simpleLogin" : { - "description" : "Session generated from a simple login module (like basic or ldap)", - "type" : "boolean" - }, - "expiredAt" : { - "description" : "Expiration date for the session", - "type" : "number" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "lastRefresh" : { - "description" : "Last refresh of the session (OAuth with refresh tokens)", - "type" : "number" - } - } - }, - "otoroshi.next.plugins.NoopSpanExporter" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.GeolocationSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.IpStackGeolocationSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.MaxmindGeolocationSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.models.NoneGeolocationSettings" - } ] - }, - "otoroshi.events.AlertEvent" : { - "type" : "object", - "description" : "Alert trail event" - }, - "otoroshi.models.ApiDescriptor" : { - "description" : "Represent if a service exposes an API with an optional url to an openapi descriptor", - "type" : "object", - "properties" : { - "exposeApi" : { - "description" : "Is this an API", - "type" : "boolean" - }, - "openApiDescriptorUrl" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "openapi descriptor url" - } - } - }, - "otoroshi.auth.SessionCookieValues" : { - "description" : "The configuration for session cookie", - "type" : "object", - "properties" : { - "httpOnly" : { - "description" : "Is cookie accessible on server side only", - "type" : "boolean" - }, - "secure" : { - "description" : "Is cookie for https only", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesIngressToDescriptor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.RBAC" : { - "description" : "Plugin to apply RBAC", - "type" : "object", - "properties" : { - "roles" : { - "description" : "roles field name", - "type" : "string" - }, - "allow" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed roles" - }, - "allow_all" : { - "description" : "Needs to have all allowed roles", - "type" : "boolean" - }, - "role_prefix" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional value that will prefix roles in tokens" - }, - "jwt_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in jwt token user" - }, - "apikey_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in an apikey" - }, - "deny" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Denied roles" - }, - "user_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in a user" - }, - "deny_all" : { - "description" : "Needs to have all denied roles", - "type" : "boolean" - } - } - }, - "otoroshi.utils.letsencrypt.LetsEncryptSettings" : { - "description" : "Settings for connection to a let's encrypt (or ACME) server", - "type" : "object", - "properties" : { - "privateKey" : { - "description" : "Let's encrypt (ACME) private key", - "type" : "string" - }, - "contacts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Let's encrypt (ACME) contacts" - }, - "emails" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Let's encrypt (ACME) contact emails" - }, - "enabled" : { - "description" : "Let's encrypt (ACME) enabled", - "type" : "boolean" - }, - "publicKey" : { - "description" : "Let's encrypt (ACME) public key", - "type" : "string" - }, - "server" : { - "description" : "Let's encrypt (ACME) server", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgTlsConfig" : { - "description" : "TLS settings for the http client", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Enabled", - "type" : "boolean" - }, - "certs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Trusted cert. ids" - }, - "loose" : { - "description" : "Loose verification", - "type" : "boolean" - }, - "trust_all" : { - "description" : "Trust any certificate", - "type" : "boolean" - }, - "trusted_certs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Trusted cert. ids" - } - } - }, - "otoroshi.models.ApiKeyRouteMatcher" : { - "description" : "Routing settings based on apikeys metadata and tags", - "type" : "object", - "properties" : { - "oneTagIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "outing if one tag presents in apikey" - }, - "noneMetaKeysIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Routing if none meta keys presents in apikey" - }, - "oneMetaIn" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Routing if one meta presents in apikey" - }, - "oneMetaKeyIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Routing if one meta key presents in apikey" - }, - "allMetaKeysIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Routing if all meta keys presents in apikey" - }, - "noneTagIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Routing if none tags presents in apikey" - }, - "allTagsIn" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Routing if all tags presents in apikey" - }, - "allMetaIn" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Routing if all meta presents in apikey" - }, - "noneMetaIn" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Routing if none meta presents in apikey" - } - } - }, - "otoroshi.next.plugins.SOAPAction" : { - "description" : "Plugin to call SOAP service", - "type" : "object", - "properties" : { - "jq_response_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform response body" - }, - "jq_request_filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform request body" - }, - "preserve_query" : { - "description" : "Preserve query params", - "type" : "boolean" - }, - "convert_request_body_to_xml" : { - "description" : "Convert json body to xml", - "type" : "boolean" - }, - "charset" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The body charset" - }, - "url" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "SOAP endpoint" - }, - "action" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The soap action if one" - }, - "envelope" : { - "description" : "The soap envelope to call", - "type" : "string" - } - } - }, - "otoroshi.next.models.StoredNgBackendDataStore" : { - "description" : "The datastore for backend", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgApikeyExtractorJwt" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "cookie_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the cookies to extract" - }, - "key_pair_signed" : { - "description" : "Is it asymmetricaly signed", - "type" : "boolean" - }, - "query_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the query param to extract" - }, - "secret_signed" : { - "description" : "Is it symmetricaly signed", - "type" : "boolean" - }, - "enabled" : { - "description" : "Is it enabled", - "type" : "boolean" - }, - "include_request_attrs" : { - "description" : "Does the jwt token need to include current request attributes to work", - "type" : "boolean" - }, - "header_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the header to extract" - } - } - }, - "otoroshi.models.Outage" : { - "description" : "A snowmonkey outage model", - "type" : "object", - "properties" : { - "descriptorName" : { - "description" : "Service descriptor name", - "type" : "string" - }, - "descriptorId" : { - "description" : "Service descriptor id", - "type" : "string" - }, - "until" : { - "description" : "Outage ending date", - "type" : "string" - }, - "duration" : { - "description" : "Outage duration", - "type" : "number" - }, - "startedAt" : { - "description" : "Outage starting date", - "type" : "number" - } - } - }, - "otoroshi.utils.JsonPathValidator" : { - "description" : "Validator based on JsonPath", - "type" : "object", - "properties" : { - "path" : { - "description" : "The path to find the validated value", - "type" : "string" - }, - "value" : { - "description" : "The expected value", - "type" : "object" - } - } - }, - "otoroshi.next.plugins.XForwardedHeaders" : { - "description" : "Plugin to add X-Forwarded headers in a request", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.GoReplayS3Settings" : { - "description" : "Settings to export to a S3 bucket", - "type" : "object", - "properties" : { - "s3" : { - "description" : "S3 bucket access settings", - "$ref" : "#/components/schemas/otoroshi.storage.drivers.inmemory.S3Configuration" - }, - "captureRequests" : { - "description" : "Enable request capture", - "type" : "boolean" - }, - "methods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Filter on http methods" - }, - "maxFileSize" : { - "format" : "int64", - "description" : "Max file size for rolling", - "type" : "integer" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "preferBackendRequest" : { - "description" : "Capture internal requests instead of external", - "type" : "boolean" - }, - "captureResponses" : { - "description" : "Enable response capture", - "type" : "boolean" - }, - "preferBackendResponse" : { - "description" : "Capture internal responses instead of external", - "type" : "boolean" - } - } - }, - "otoroshi.utils.ConcurrentMutableTypedMap" : { - "description" : "A concurrent map with typed keys", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.biscuit.PubKeyBiscuitToken" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "token" : { - "description" : "the current token", - "type" : "string" - } - } - }, - "otoroshi.utils.mailer.SendgridSettings" : { - "description" : "Settings for the sendgrid mailer", - "type" : "object", - "properties" : { - "apiKey" : { - "description" : "Sendgrid apikey", - "type" : "string" - }, - "to" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.EmailLocation" - }, - "description" : "Destination email address" - }, - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - } - } - }, - "otoroshi.gateway.CircuitBreakersHolder" : { - "description" : "Internal component to hold current circuit breakers and their configuration", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgAuthModuleConfig" : { - "description" : "Configuration for AuthModule", - "type" : "object", - "properties" : { - "module" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The id of the auth. module" - }, - "pass_with_apikey" : { - "description" : "Pass the request if an apikey is present", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.NgChaosConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "large_request_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLargeRequestFaultConfig" - } ], - "description" : "Config. for large request body faults" - }, - "large_response_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLargeResponseFaultConfig" - } ], - "description" : "Config. for large response faults" - }, - "latency_injection_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgLatencyInjectionFaultConfig" - } ], - "description" : "Config. for latency injection faults" - }, - "bad_responses_fault_config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgBadResponsesFaultConfig" - } ], - "description" : "Config. for bad responses faults" - } - } - }, - "ByteStreamBody" : { - "type" : "string", - "description" : "" - }, - "play.api.libs.ws.DefaultWSProxyServer" : { - "type" : "object", - "properties" : { - "host" : { - "type" : "string", - "description" : "The hostname of the proxy server." - }, - "port" : { - "type" : "string", - "description" : "The port of the proxy server." - }, - "protocol" : { - "type" : "string", - "description" : "The protocol of the proxy server. Use \"http\" or \"https\". Defaults to \"http\" if not specified." - }, - "principal" : { - "type" : "string", - "description" : "The principal (aka username) of the credentials for the proxy server." - }, - "password" : { - "type" : "string", - "description" : "The password for the credentials for the proxy server." - }, - "ntlmDomain" : { - "type" : "string", - "description" : "The ntlm domain for the proxy server." - }, - "encoding" : { - "type" : "string", - "description" : "The realm's charset." - }, - "nonProxyHosts" : { - "type" : "string", - "description" : "The non proxied hosts" - } - }, - "description" : "Proxy server" - }, - "otoroshi.plugins.loggers.BodyLogger" : { - "description" : "Plugin to log http bodies", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.biscuit.AccessValidatorContext" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "ctx" : { - "description" : "Current context", - "$ref" : "#/components/schemas/otoroshi.script.AccessContext" - } - } - }, - "otoroshi.next.plugins.MockResponse" : { - "description" : "Plugin to mock responses", - "type" : "object", - "properties" : { - "path" : { - "description" : "The path for the response", - "type" : "string" - }, - "body" : { - "description" : "The body of the response", - "type" : "string" - }, - "status" : { - "format" : "int32", - "description" : "The status of the response", - "type" : "integer" - }, - "method" : { - "description" : "The method for the response", - "type" : "string" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The headers of the response" - } - } - }, - "PemCertificateBody" : { - "type" : "string", - "description" : "PEM encoded certificate" - }, - "otoroshi.next.plugins.GlobalMaintenanceMode" : { - "description" : "Plugin for maintainance mode", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.LargeRequestFaultConfig" : { - "description" : "Settings for a large request fault (chaos engineering)", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0", - "type" : "number" - }, - "additionalRequestSize" : { - "format" : "int32", - "description" : "The size added to the request body in bytes. Added payload will be spaces only.", - "type" : "integer" - } - } - }, - "otoroshi.next.models.NgBackend" : { - "description" : "A backend representation with it's targets, load balancing and general settings", - "type" : "object", - "properties" : { - "root" : { - "description" : "The root path of the backend or the full rewrite path", - "type" : "string" - }, - "health_check" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/otoroshi.models.HealthCheck" - } ], - "description" : "Healthcheck config og the backend" - }, - "client" : { - "description" : "Client config. of the backend", - "$ref" : "#/components/schemas/otoroshi.next.models.NgClientConfig" - }, - "load_balancing" : { - "description" : "Loadbalancing config og the backend", - "$ref" : "#/components/schemas/otoroshi.models.LoadBalancing" - }, - "rewrite" : { - "description" : "Does the backend performs a full url rewrite ?", - "type" : "boolean" - }, - "target_refs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "List of NgStoredBackend ids" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - }, - "description" : "The targets of the backend" - } - } - }, - "ExperimentalFormResponse" : { - "type" : "object", - "description" : "The representation of a form to configure a plugin or an entity" - }, - "otoroshi.next.plugins.NgApikeyExtractorClientId" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "header_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the header to extract" - }, - "query_name" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "The name of the query param to extract" - }, - "enabled" : { - "description" : "Is it enabled", - "type" : "boolean" - } - } - }, - "OutagesList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Outage" - } - }, - "otoroshi.plugins.mirror.MirroringPluginConfig" : { - "description" : "Configuration for MirroringPlugin", - "type" : "object", - "properties" : { - "conf" : { - "description" : "Current conf", - "type" : "object" - } - } - }, - "PluginDescriptionsResponse" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/PluginDescription" - } - }, - "otoroshi.script.PreRoutingRef" : { - "description" : "References to pre-routing plugins", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "pre-routing plugins enabled", - "type" : "boolean" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Excluded paths" - }, - "refs" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Enabled plugins" - }, - "config" : { - "description" : "pre-routing plugins configuration", - "type" : "object" - } - } - }, - "otoroshi.plugins.biscuit.BiscuitConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "facts" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit facts" - }, - "publicKey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Biscuit public key for validation" - }, - "resources" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit resources" - }, - "enforce" : { - "description" : "Enforce biscuit validation", - "type" : "boolean" - }, - "extractorName" : { - "description" : "The name for the location", - "type" : "string" - }, - "checks" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit checks" - }, - "extractor" : { - "description" : "Biscuit location (header, cookie, query)", - "type" : "string" - }, - "revocation_ids" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Ids of revoked tokens" - }, - "rules" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Biscuit rules" - } - } - }, - "otoroshi.next.plugins.NgJwtVerificationConfig" : { - "description" : "Configuration for JwtVerification", - "type" : "object", - "properties" : { - "verifiers" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Id of the jwt verifiers" - } - } - }, - "otoroshi.next.plugins.W3CTracingConfig" : { - "description" : "Configuration for W3CTracing", - "type" : "object", - "properties" : { - "kind" : { - "description" : "Kind of distributed tracing collector (jaeger, zipkin)", - "$ref" : "#/components/schemas/otoroshi.next.plugins.W3CTracingConfigKind" - }, - "endpoint" : { - "description" : "Endpoint of distributed tracing collection", - "type" : "string" - }, - "timeout" : { - "format" : "int64", - "description" : "Request timeout", - "type" : "integer" - }, - "baggage" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Support baggage" - } - } - }, - "otoroshi.next.plugins.AuthorisationException" : { - "description" : "???", - "type" : "object", - "properties" : { - "message" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgCacheConnectionSettings" : { - "description" : "The settings for http cached connection at host level", - "type" : "object", - "properties" : { - "queue_size" : { - "format" : "int32", - "description" : "How much request can be queue before dropping it", - "type" : "integer" - }, - "enabled" : { - "description" : "Is cached connection enabled", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.geoloc.IpStackGeolocationHelper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.DataExporterConfig" : { - "description" : "Data exporter settings", - "type" : "object", - "properties" : { - "desc" : { - "description" : "Description", - "type" : "string" - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "bufferSize" : { - "format" : "int32", - "description" : "Number of events in buffer", - "type" : "integer" - }, - "jsonWorkers" : { - "format" : "int32", - "description" : "Number of workers that transform events", - "type" : "integer" - }, - "groupDuration" : { - "description" : "The max duration before sending group", - "type" : "number" - }, - "groupSize" : { - "format" : "int32", - "description" : "The max size of events group before sending", - "type" : "integer" - }, - "type" : { - "description" : "Entity type", - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfigType" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - }, - "sendWorkers" : { - "format" : "int32", - "description" : "Number of workers that sends events", - "type" : "integer" - }, - "id" : { - "description" : "Id of the exporter", - "type" : "string" - }, - "name" : { - "description" : "Entity name", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "config" : { - "description" : "Exporter config", - "$ref" : "#/components/schemas/otoroshi.models.Exporter" - }, - "projection" : { - "description" : "Event projection", - "type" : "object" - }, - "enabled" : { - "description" : "Is the exporter enabled", - "type" : "boolean" - }, - "filtering" : { - "description" : "Filtering options", - "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfigFiltering" - } - } - }, - "otoroshi.next.plugins.NgEndlessHttpResponseConfig" : { - "description" : "Configuration for EndlessHttpResponse", - "type" : "object", - "properties" : { - "finger" : { - "description" : "Using emoji instead of 0 in the response", - "type" : "boolean" - }, - "addresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "IP address that will get endless responses" - } - } - }, - "otoroshi.ssl.pki.models.GenKeyPairResponse" : { - "description" : "Response for a keypair generation operation", - "type" : "object", - "properties" : { - "publicKey" : { - "description" : "Public key (PEM encoded)", - "type" : "string" - }, - "privateKey" : { - "description" : "Private key (PEM encoded)", - "type" : "string" - } - } - }, - "BulkBody" : { - "type" : "string", - "description" : "Body composed of stringified JSON lines, each one representing an entity" - }, - "otoroshi.plugins.discovery.DiscoveryJob" : { - "description" : "Plugin that add services discovery to otoroshi", - "type" : "object", - "properties" : { } - }, - "PemCsrBody" : { - "type" : "string", - "description" : "PEM encoded csr" - }, - "Unknown" : { - "type" : "object", - "description" : "value used by the openapi generator when no matching type found. Should be fixed in a near future." - }, - "otoroshi.plugins.authcallers.OAuth2CallerConfig" : { - "description" : "Configuration for OAuth2Caller", - "type" : "object", - "properties" : { - "method" : { - "description" : "Http method to talk with the id server", - "type" : "string" - }, - "url" : { - "description" : "Url of the id server", - "type" : "string" - }, - "tlsConfig" : { - "description" : "Current tls config to talk to the id server", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "kind" : { - "description" : "client_credentials or password", - "$ref" : "#/components/schemas/otoroshi.plugins.authcallers.OAuth2Kind" - }, - "password" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional password for password flow" - }, - "cacheTokenSeconds" : { - "description" : "How long will the token be cached before reaching out to the id server", - "type" : "number" - }, - "headerValueFormat" : { - "description" : "The header format to pass the token", - "type" : "string" - }, - "user" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional user for password flow" - }, - "headerName" : { - "description" : "The header name to pass the token", - "type" : "string" - }, - "clientSecret" : { - "description" : "The client secret", - "type" : "string" - }, - "scope" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional request scope" - }, - "jsonPayload" : { - "description" : "Use a json payload instead of a urlformencoded one", - "type" : "boolean" - }, - "clientId" : { - "description" : "The client id", - "type" : "string" - }, - "audience" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "An optional audiance" - } - } - }, - "otoroshi.next.plugins.MissingHeadersOut" : { - "description" : "Plugin to add headers to a response", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers added to the response if missing" - } - } - }, - "otoroshi.plugins.oidc.ThirdPartyApiKeyConfigType" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.authcallers.BasicAuthCaller" : { - "description" : "Plugin that can call a basic auth. backend", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.Keys" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.CustomHeadersAuthConstraints" : { - "description" : "Settings to extract apikey from a custom headers", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Constraint enabled", - "type" : "boolean" - }, - "clientIdHeaderName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to find client_id" - }, - "clientSecretHeaderName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Header name to find client_secret" - } - } - }, - "otoroshi.models.TlsSettings" : { - "description" : "Global TLS settings. The default domain that will be picked if no certificate matches the current request", - "type" : "object", - "properties" : { - "trustedCAsServer" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "List for CAs trusted by otoroshi when performing TLS termination" - }, - "includeJdkCaClient" : { - "description" : "Use known JDK CAs to build trust when performing request from otoroshi to backends", - "type" : "boolean" - }, - "randomIfNotFound" : { - "description" : "Use a random one", - "type" : "boolean" - }, - "defaultDomain" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Default domain to choose if not found from current certificates" - }, - "includeJdkCaServer" : { - "description" : "Use known JDK CAs to build trust for incoming request", - "type" : "boolean" - } - } - }, - "otoroshi.models.MetricsSettings" : { - "description" : "Settings to export to otoroshi metrics", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "labels" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Exported labels for prometheus" - } - } - }, - "otoroshi.models.Sign" : { - "description" : "jwt token re-sign policy settings", - "type" : "object", - "properties" : { - "algoSettings" : { - "description" : "Re-signing jwt token settings", - "$ref" : "#/components/schemas/otoroshi.models.AlgoSettings" - }, - "verificationSettings" : { - "description" : "Verification settings", - "$ref" : "#/components/schemas/otoroshi.models.VerificationSettings" - }, - "type" : { - "description" : "the kind of strategy", - "type" : "string", - "enum" : [ "PassThrough", "Sign", "Transform", "DefaultToken" ] - } - } - }, - "otoroshi.plugins.mirror.MirroringEvent" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "ctx" : { - "description" : "Current request context", - "$ref" : "#/components/schemas/otoroshi.plugins.mirror.RequestContext" - } - } - }, - "otoroshi.models.PassThrough" : { - "description" : "jwt token validation policicy that just validate the token", - "type" : "object", - "properties" : { - "verificationSettings" : { - "description" : "Verification settings", - "$ref" : "#/components/schemas/otoroshi.models.VerificationSettings" - }, - "type" : { - "description" : "the kind of strategy", - "type" : "string", - "enum" : [ "PassThrough", "Sign", "Transform", "DefaultToken" ] - } - } - }, - "otoroshi.plugins.external.ExternalHttpValidatorConfig" : { - "description" : "Configuration for ExternalHttpValidator", - "type" : "object", - "properties" : { - "config" : { - "description" : "Configuration for external http validation", - "type" : "object" - } - } - }, - "otoroshi.plugins.geoloc.MaxMindGeolocationInfoExtractor" : { - "description" : "Plugin that extracts geolocation based on maxmind db", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgHeaderNamesConfig" : { - "description" : "Configuration for headers plugins", - "type" : "object", - "properties" : { - "names" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Name of the headers" - } - } - }, - "otoroshi.events.PulsarConfig" : { - "description" : "Settings for connection to a pulsar cluster", - "type" : "object", - "properties" : { - "mtlsConfig" : { - "description" : "TLS settings to access pulsar", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - }, - "tlsTrustCertsFilePath" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Truststore path" - }, - "namespace" : { - "description" : "Pulsar namespace", - "type" : "string" - }, - "topic" : { - "description" : "Pulsar topic", - "type" : "string" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "uri" : { - "description" : "Pulsar access uri", - "type" : "string" - }, - "tenant" : { - "description" : "Pulsar tenant", - "type" : "string" - } - } - }, - "otoroshi.auth.SamlAuthModuleConfig" : { - "description" : "Configuration of SAML Authentication module", - "type" : "object", - "properties" : { - "validateSignature" : { - "description" : "Indicates if SAML response signature has to be validate when otoroshi got SAML responses from identity provider", - "type" : "boolean" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata of the SAML module" - }, - "ssoProtocolBinding" : { - "description" : "Protocol binding used to send login request to identity provider", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLProtocolBinding" - }, - "sessionCookieValues" : { - "description" : "Settings for the session cookie", - "$ref" : "#/components/schemas/otoroshi.auth.SessionCookieValues" - }, - "validatingCertificates" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Certificates used to validate SAML response signature" - }, - "signature" : { - "description" : "Algorithm and canonicalization method to sign SAML documents", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLSignature" - }, - "credentials" : { - "description" : "Certificates and private keys to sign and encrypt SAML documents/assertions", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLCredentials" - }, - "validateAssertions" : { - "description" : "Indicates if assertions have to be validate when otoroshi got SAML responses from identity provider", - "type" : "boolean" - }, - "type" : { - "description" : "the type of the module", - "type" : "string", - "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] - }, - "userValidators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "Validators that will check if the current user is authorized after successful login" - }, - "_loc" : { - "description" : "Location of the SAML module", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "issuer" : { - "description" : "Issuer of the SAML requests", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "SAML module tags" - }, - "sessionMaxAge" : { - "format" : "int32", - "description" : "Max age of the session", - "type" : "integer" - }, - "usedNameIDAsEmail" : { - "description" : "Is name ID used as email ?", - "type" : "boolean" - }, - "singleLogoutUrl" : { - "description" : "URL used by otoroshi to disconnect users from identity provider", - "type" : "string" - }, - "name" : { - "description" : "Name of the SAML module", - "type" : "string" - }, - "emailAttributeName" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Field name to find email in user profile returned by identity provider" - }, - "clientSideSessionEnabled" : { - "description" : "???", - "type" : "boolean" - }, - "singleSignOnUrl" : { - "description" : "URL used by otoroshi to redirect users to identity provider login page", - "type" : "string" - }, - "nameIDFormat" : { - "description" : "Format of the name ID", - "$ref" : "#/components/schemas/otoroshi.auth.NameIDFormat" - }, - "singleLogoutProtocolBinding" : { - "description" : "Protocol binding used by identity provider to logout users", - "$ref" : "#/components/schemas/otoroshi.auth.SAMLProtocolBinding" - }, - "id" : { - "description" : "Id of the SAML Auth module", - "type" : "string" - }, - "desc" : { - "description" : "Description of the SAML Auth module", - "type" : "string" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesCRDsJob" : { - "description" : "Plugin to import entities from kubernetes CRDs", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.Restrictions" : { - "description" : "Http requests restrictions for a service or an apikey", - "type" : "object", - "properties" : { - "forbidden" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.RestrictionPath" - }, - "description" : "Forbidden paths (return 403)" - }, - "allowed" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.RestrictionPath" - }, - "description" : "Allowed paths" - }, - "notFound" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.RestrictionPath" - }, - "description" : "Not found paths (return 404)" - }, - "allowLast" : { - "description" : "Evalute allowed paths after everything else", - "type" : "boolean" - }, - "enabled" : { - "description" : "Restrictions enabled", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.NgLargeRequestFaultConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The ratio of requests impacted", - "type" : "number" - }, - "additional_request_size" : { - "format" : "int32", - "description" : "Amount of bytes added of the request body", - "type" : "integer" - } - } - }, - "otoroshi.auth.PKCEConfig" : { - "description" : "Settings for PKCE challenge (OAuth 2.1)", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "Is PKCE challenge enabled", - "type" : "boolean" - }, - "algorithm" : { - "description" : "Hashing algorithm used in PKCE challenge", - "type" : "string" - } - } - }, - "otoroshi.events.StatsdConfig" : { - "description" : "Settings for connection to a statsd agent", - "type" : "object", - "properties" : { - "datadog" : { - "description" : "Datadog agent", - "type" : "boolean" - }, - "host" : { - "description" : "The host of the StatsD agent", - "type" : "string" - }, - "port" : { - "format" : "int32", - "description" : "The port of the StatsD agent", - "type" : "integer" - } - } - }, - "otoroshi.next.plugins.RBACConfig" : { - "description" : "Configuration for RBAC", - "type" : "object", - "properties" : { - "roles" : { - "description" : "roles field name", - "type" : "string" - }, - "allow" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Allowed roles" - }, - "allow_all" : { - "description" : "Needs to have all allowed roles", - "type" : "boolean" - }, - "role_prefix" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Optional value that will prefix roles in tokens" - }, - "jwt_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in jwt token user" - }, - "apikey_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in an apikey" - }, - "deny" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Denied roles" - }, - "user_path" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Where to find role field in a user" - }, - "deny_all" : { - "description" : "Needs to have all denied roles", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.biscuit.VerificationContext" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgCanarySettings" : { - "description" : "Configuration for CanaryMode", - "type" : "object", - "properties" : { - "traffic" : { - "format" : "double", - "description" : "Traffic ratio for canary targets", - "type" : "number" - }, - "root" : { - "description" : "Root for canary targets", - "type" : "string" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - }, - "description" : "Canary targets" - } - } - }, - "otoroshi.models.JWKSAlgoSettings" : { - "description" : "Settings to use keypair from JWKS for verification", - "type" : "object", - "properties" : { - "kty" : { - "description" : "Key type", - "type" : "string" - }, - "proxy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "$ref" : "#/components/schemas/play.api.libs.ws.WSProxyServer" - } ], - "description" : "Web proxy for http client" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Http header when fetching JWKS" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - }, - "ttl" : { - "description" : "Cache ttl", - "type" : "number" - }, - "url" : { - "description" : "JWKS url", - "type" : "string" - }, - "timeout" : { - "description" : "Timeout when fetching JWKS", - "type" : "number" - }, - "tlsConfig" : { - "description" : "TLS config", - "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" - } - } - }, - "otoroshi.plugins.hmac.HMACUtils" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.authcallers.ForceRetryException" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.StaticBackend" : { - "description" : "???", - "type" : "object", - "properties" : { - "root_path" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.GraphlCallException" : { - "description" : "???", - "type" : "object", - "properties" : { - "message" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.next.models.RoutingStrategy" : { - "description" : "The routing strategy", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.IpAddressBlockList" : { - "description" : "Plugin to block only some ip addresses", - "type" : "object", - "properties" : { - "addresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "The list of blocked ip addresses of cidr blocks" - } - } - }, - "otoroshi.plugins.biscuit.SealedBiscuitToken" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "token" : { - "description" : "the current token", - "type" : "string" - } - } - }, - "otoroshi.models.IpFiltering" : { - "description" : "Settings for ip address filtering for a service or globally", - "type" : "object", - "properties" : { - "whitelist" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Whitelisted IP addresses" - }, - "blacklist" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Blacklisted IP addresses" - } - } - }, - "otoroshi.plugins.quotas.ServiceQuotas" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.jobs.kubernetes.KubernetesCertSyncJob" : { - "description" : "Plugin to sync kubernetes certificates with otoroshi", - "type" : "object", - "properties" : { } - }, - "otoroshi.ssl.pki.models.GenCsrResponse" : { - "description" : "Response for a csr generation operation", - "type" : "object", - "properties" : { - "csr" : { - "description" : "CSR (PEM encoded)", - "type" : "string" - }, - "publicKey" : { - "description" : "Public key (PEM encoded)", - "type" : "string" - }, - "privateKey" : { - "description" : "Private key (PEM encoded)", - "type" : "string" - } - } - }, - "otoroshi.next.models.NgMatchedRoute" : { - "description" : "A matched route in the new router", - "type" : "object", - "properties" : { - "route" : { - "description" : "Current matched route", - "$ref" : "#/components/schemas/otoroshi.next.models.NgRoute" - }, - "path" : { - "description" : "Current matched path", - "type" : "string" - }, - "no_more_segments" : { - "description" : "Is the path fully matched", - "type" : "boolean" - } - } - }, - "otoroshi.auth.SAMLProtocolBinding" : { - "description" : "Protocol binding used during SAML requests", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.MaxmindGeolocationSettings" : { - "description" : "Settings for connection to a maxmind db", - "type" : "object", - "properties" : { - "path" : { - "description" : "Maxmlind db file path", - "type" : "string" - }, - "type" : { - "description" : "the kind of geolocation", - "type" : "string", - "enum" : [ "none", "maxmind", "ipstack" ] - }, - "enabled" : { - "description" : "Geolocation using maxmind db enabled", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.NgLargeResponseFaultConfig" : { - "description" : "Configuration for SnowMonkeyChaos", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The ratio of responses impacted", - "type" : "number" - }, - "additional_response_size" : { - "format" : "int32", - "description" : "Amount of bytes added of the response body", - "type" : "integer" - } - } - }, - "otoroshi.models.LatencyInjectionFaultConfig" : { - "description" : "Settings for a latency injection fault (chaos engineering)", - "type" : "object", - "properties" : { - "ratio" : { - "format" : "double", - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0", - "type" : "number" - }, - "from" : { - "description" : "The start range of latency added to the request", - "type" : "number" - }, - "to" : { - "description" : "The end range of latency added to the request", - "type" : "number" - } - } - }, - "otoroshi.plugins.oidc.OIDCAccessTokenAsApikey" : { - "description" : "Plugin to use OIDC token as apikey", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgIpAddressesConfig" : { - "description" : "Configuration for ip address related plugins", - "type" : "object", - "properties" : { - "addresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Ip addresses targeted" - } - } - }, - "otoroshi.models.RSAKPAlgoSettings" : { - "description" : "Settings to use RSA signing algorithm from a certificate keypair", - "type" : "object", - "properties" : { - "size" : { - "format" : "int32", - "description" : "SHA function size", - "type" : "integer" - }, - "certId" : { - "description" : "Certificate id", - "type" : "string" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.utils.mailer.MailerSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.ConsoleMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.GenericMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailgunSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.MailjetSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.NoneMailerSettings" - }, { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.SendgridSettings" - } ] - }, - "otoroshi.auth.Oauth1ModuleConfig" : { - "description" : "Configuration of OAuth 1.0 module", - "type" : "object", - "properties" : { - "profileURL" : { - "description" : "URL fetch by otoroshi to get user information from identity provider", - "type" : "string" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "The metadata of the OAuth 1 module" - }, - "authorizeURL" : { - "description" : "The authorize URL used to initiates the authorization flow that authenticates the user with the Identity Provider", - "type" : "string" - }, - "requestTokenURL" : { - "description" : "URL fetch to get a request token during the first step of the authorization OAuth 1 flow", - "type" : "string" - }, - "sessionCookieValues" : { - "description" : "Settings for the session cookie", - "$ref" : "#/components/schemas/otoroshi.auth.SessionCookieValues" - }, - "type" : { - "description" : "the type of the module", - "type" : "string", - "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] - }, - "httpMethod" : { - "description" : "Method used to fetch access and request token", - "$ref" : "#/components/schemas/otoroshi.auth.OAuth1Provider" - }, - "userValidators" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.JsonPathValidator" - }, - "description" : "Validators that will check if the current user is authorized after successful login" - }, - "_loc" : { - "description" : "The location of the OAuth 1 module", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "OAuth module tags" - }, - "sessionMaxAge" : { - "format" : "int32", - "description" : "Max age of the session", - "type" : "integer" - }, - "consumerSecret" : { - "description" : "Client secret obtained from identity provider configuration", - "type" : "string" - }, - "accessTokenURL" : { - "description" : "Endpoint requested by otoroshi to get access token during the authorization OAuth1 flow", - "type" : "string" - }, - "name" : { - "description" : "The name of the OAuth 1 module", - "type" : "string" - }, - "rightsOverride" : { - "type" : "object", - "additionalProperties" : { - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "description" : "Overrides user rights of users connected by OAuth1 module" - }, - "clientSideSessionEnabled" : { - "description" : "???", - "type" : "boolean" - }, - "callbackURL" : { - "description" : "The location where the identity provider returns a browser after the user finishes authenticating with their IDP", - "type" : "string" - }, - "id" : { - "description" : "Id of the module", - "type" : "string" - }, - "consumerKey" : { - "description" : "Client ID obtained on identity provider", - "type" : "string" - }, - "desc" : { - "description" : "Description of the oauth 1 module", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.JsonToXmlRequest" : { - "description" : "Plugin to transform json body to xml", - "type" : "object", - "properties" : { - "filter" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "JQ filter to transform json entity" - } - } - }, - "otoroshi.plugins.defer.DeferPlugin" : { - "description" : "Plugin that defers http responses", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.StaticResponse" : { - "description" : "Plugin to return static responses", - "type" : "object", - "properties" : { - "status" : { - "format" : "int32", - "description" : "Status of the response", - "type" : "integer" - }, - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers of the response" - }, - "body" : { - "description" : "Body of the response", - "type" : "string" - } - } - }, - "otoroshi.next.plugins.OverrideHost" : { - "description" : "Plugin to override backend host header", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgPublicPrivatePathsConfig" : { - "description" : "Configuration for PublicPrivatePaths", - "type" : "object", - "properties" : { - "strict" : { - "description" : "apikey only", - "type" : "boolean" - }, - "public_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths that should not have user or apikey to pass" - }, - "private_patterns" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Paths that should have user or apikey to pass" - } - } - }, - "otoroshi.models.InQueryParam" : { - "description" : "JWT token location (query param)", - "type" : "object", - "properties" : { - "name" : { - "description" : "Query param name", - "type" : "string" - }, - "type" : { - "description" : "the kind of location", - "type" : "string", - "enum" : [ "InQueryParam", "InHeader", "InCookie" ] - } - } - }, - "otoroshi.plugins.clientcert.ClientCertChainHeader" : { - "description" : "Plugin that can pass client certificates as header to the backends", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.security.SecurityTxt" : { - "description" : "Plugin that serves /.well-known/security.txt resources", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.EntityLocation" : { - "description" : "Location of any entity (teams and organization)", - "type" : "object", - "properties" : { - "tenant" : { - "description" : "Organization of the current entity", - "$ref" : "#/components/schemas/otoroshi.models.TenantId" - }, - "teams" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.TeamId" - }, - "description" : "Teams of the current entity" - } - } - }, - "otoroshi.next.plugins.RoutingRestrictions" : { - "description" : "Configuration for NgRestrictions", - "type" : "object", - "properties" : { - "allow_last" : { - "description" : "Evaluates allowed paths after forbidden and not found", - "type" : "boolean" - }, - "allowed" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Allowed paths" - }, - "forbidden" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Forbidden paths" - }, - "not_found" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgRestrictionPath" - }, - "description" : "Not found paths" - } - } - }, - "otoroshi.next.plugins.GlobalPerIpAddressThrottling" : { - "description" : "Plugin for ip address throttling", - "type" : "object", - "properties" : { } - }, - "otoroshi.events.AuditEvent" : { - "type" : "object", - "description" : "Audit trail event" - }, - "otoroshi.plugins.izanami.IzanamiProxy" : { - "description" : "Plugin to proxy izanami", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.ErrorTemplate" : { - "description" : "Service descriptor error template", - "type" : "object", - "properties" : { - "template50x" : { - "description" : "The 50x error html template", - "type" : "string" - }, - "templateMaintenance" : { - "description" : "The maintenance html template", - "type" : "string" - }, - "templateBuild" : { - "description" : "The build html template", - "type" : "string" - }, - "serviceId" : { - "description" : "Service id for this template", - "type" : "string" - }, - "messages" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Map of messages" - }, - "template40x" : { - "description" : "The 40x error html template", - "type" : "string" - } - } - }, - "otoroshi.utils.mailer.NoneMailerSettings" : { - "description" : "Settings for the /dev/null mailer", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - } - } - }, - "otoroshi.next.plugins.MockField" : { - "description" : "???", - "type" : "object", - "properties" : { - "field_name" : { - "description" : "???", - "type" : "string" - }, - "field_type" : { - "description" : "???", - "type" : "string" - }, - "value" : { - "description" : "???", - "type" : "object" - } - } - }, - "otoroshi.next.plugins.EndlessHttpResponse" : { - "description" : "Plugin for endless response", - "type" : "object", - "properties" : { - "finger" : { - "description" : "Using emoji instead of 0 in the response", - "type" : "boolean" - }, - "addresses" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "IP address that will get endless responses" - } - } - }, - "otoroshi.models.SecComInfoTokenVersion" : { - "type" : "string", - "enum" : [ "Legacy", "Latest" ], - "description" : "Version of the info token" - }, - "otoroshi.next.plugins.S3Backend" : { - "description" : "???", - "type" : "object", - "properties" : { - "writeEvery" : { - "description" : "???", - "type" : "number" - }, - "chunkSize" : { - "format" : "int32", - "description" : "???", - "type" : "integer" - }, - "bucket" : { - "description" : "???", - "type" : "string" - }, - "key" : { - "description" : "???", - "type" : "string" - }, - "endpoint" : { - "description" : "???", - "type" : "string" - }, - "v4auth" : { - "description" : "???", - "type" : "boolean" - }, - "access" : { - "description" : "???", - "type" : "string" - }, - "secret" : { - "description" : "???", - "type" : "string" - }, - "region" : { - "description" : "???", - "type" : "string" - } - } - }, - "otoroshi.plugins.biscuit.BiscuitHelper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "BulkPatchBody" : { - "type" : "array", - "description" : "Body composed of stringified JSON-Patch lines, each one representing updates to an entity", - "items" : { - "$ref" : "#/components/schemas/PatchDocument" - } - }, - "otoroshi.next.plugins.W3CTracing" : { - "description" : "Plugin to have distributed tracing", - "type" : "object", - "properties" : { - "kind" : { - "description" : "Kind of distributed tracing collector (jaeger, zipkin)", - "$ref" : "#/components/schemas/otoroshi.next.plugins.W3CTracingConfigKind" - }, - "endpoint" : { - "description" : "Endpoint of distributed tracing collection", - "type" : "string" - }, - "timeout" : { - "format" : "int64", - "description" : "Request timeout", - "type" : "integer" - }, - "baggage" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Support baggage" - } - } - }, - "otoroshi.next.models.NgSelectedBackendTarget" : { - "description" : "The current target", - "type" : "object", - "properties" : { - "target" : { - "description" : "The current target", - "$ref" : "#/components/schemas/otoroshi.next.models.NgTarget" - }, - "attempts" : { - "format" : "int32", - "description" : "Circuit breaker attemps", - "type" : "integer" - }, - "cb_start" : { - "format" : "int64", - "description" : "Time start of circuit breaker usage", - "type" : "integer" - } - } - }, - "GlobalConfigImportBody" : { - "type" : "object", - "description" : "" - }, - "otoroshi.auth.AuthModuleConfig" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.auth.BasicAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.GenericOauth2ModuleConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.Oauth1ModuleConfig" - }, { - "$ref" : "#/components/schemas/otoroshi.auth.SamlAuthModuleConfig" - } ] - }, - "otoroshi.next.plugins.Robots" : { - "description" : "Plugin to handle search engine bots", - "type" : "object", - "properties" : { - "robot_txt_content" : { - "description" : "Content of /robots.txt", - "type" : "string" - }, - "meta_content" : { - "description" : "content of the tag", - "type" : "string" - }, - "robot_enabled" : { - "description" : "/robots.txt enabled", - "type" : "boolean" - }, - "header_content" : { - "description" : "Content of the X-Robots-Tag headers", - "type" : "string" - }, - "header_enabled" : { - "description" : "Header enabled", - "type" : "boolean" - }, - "meta_enabled" : { - "description" : "Meta tag enabled", - "type" : "boolean" - } - } - }, - "otoroshi.utils.mailer.GenericMailerSettings" : { - "description" : "Settings for the generic mailer (http requests)", - "type" : "object", - "properties" : { - "headers" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Sender headers" - }, - "to" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.utils.mailer.EmailLocation" - }, - "description" : "Destination email address" - }, - "type" : { - "description" : "the kind of mailer", - "type" : "string", - "enum" : [ "none", "console", "generic", "mailgun", "mailjet", "sendgrid" ] - }, - "url" : { - "description" : "Sender URL", - "type" : "string" - } - } - }, - "otoroshi.models.GoReplayFileSettings" : { - "description" : "Settings to export to a file", - "type" : "object", - "properties" : { - "path" : { - "description" : "File path", - "type" : "string" - }, - "captureRequests" : { - "description" : "Enable request capture", - "type" : "boolean" - }, - "methods" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Filter on http methods" - }, - "maxFileSize" : { - "format" : "int64", - "description" : "Max file size for rolling", - "type" : "integer" - }, - "type" : { - "description" : "the kind of exporter", - "type" : "string", - "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] - }, - "preferBackendRequest" : { - "description" : "Capture internal requests instead of external", - "type" : "boolean" - }, - "captureResponses" : { - "description" : "Enable response capture", - "type" : "boolean" - }, - "preferBackendResponse" : { - "description" : "Capture internal responses instead of external", - "type" : "boolean" - } - } - }, - "Null" : { - "type" : "object", - "description" : "no value object, used to represent a None option value" - }, - "otoroshi.next.plugins.NgApikeyExtractors" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "basic" : { - "description" : "basic auth extractor config.", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractorBasic" - }, - "custom_headers" : { - "description" : "custom headers extractor config.", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractorCustomHeaders" - }, - "client_id" : { - "description" : "client id only extractor config.", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractorClientId" - }, - "jwt" : { - "description" : "jwt extractor config.", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractorJwt" - } - } - }, - "TargetsList" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/otoroshi.models.Target" - } - }, - "otoroshi.auth.Credential" : { - "description" : "Pair of raw certificate, private key and certId for SAML protocol", - "type" : "object", - "properties" : { - "certificate" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "PEM certificate used to sign SAML requests send to identity provider" - }, - "privateKey" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Private key of the certificate used to sign SAML requests send to identity provider" - }, - "certId" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Id of the certificate used to sign SAML requests send to identity provider" - }, - "useOtoroshiCertificate" : { - "description" : "Indicates if SAML requests are signed with otoroshi certificate or a PEM certificate", - "type" : "boolean" - } - } - }, - "otoroshi.next.plugins.NgRedirectionSettings" : { - "description" : "Configuration for Redirection", - "type" : "object", - "properties" : { - "code" : { - "format" : "int32", - "description" : "Redirection status code used", - "type" : "integer" - }, - "to" : { - "description" : "The redirection url", - "type" : "string" - } - } - }, - "otoroshi.models.WebAuthnOtoroshiAdmin" : { - "description" : "An otoroshi admin user that uses webauthn at login", - "type" : "object", - "properties" : { - "createdAt" : { - "description" : "User creation date", - "type" : "number" - }, - "metadata" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Entity metadata" - }, - "password" : { - "description" : "User password", - "type" : "string" - }, - "credentials" : { - "type" : "object", - "additionalProperties" : { - "type" : "object" - }, - "description" : "User webauthn credentials" - }, - "rights" : { - "description" : "User rights", - "$ref" : "#/components/schemas/otoroshi.models.UserRights" - }, - "typ" : { - "description" : "User type", - "$ref" : "#/components/schemas/otoroshi.models.OtoroshiAdminType" - }, - "handle" : { - "description" : "User webauthn handle", - "type" : "string" - }, - "label" : { - "description" : "User label", - "type" : "string" - }, - "type" : { - "description" : "the kind of admin", - "type" : "string", - "enum" : [ "simple", "webauthn" ] - }, - "_loc" : { - "description" : "Entity location", - "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" - }, - "username" : { - "description" : "User username", - "type" : "string" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - }, - "description" : "Entity tags" - } - } - }, - "otoroshi.plugins.jobs.kubernetes.OtoroshiToKubernetesCertSyncJob" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.plugins.biscuit.BiscuitExtractor" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "PatchBody" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/PatchDocument" - } - }, - "otoroshi.plugins.jobs.kubernetes.OtoAnnotationConfig" : { - "description" : "Internal api", - "type" : "object", - "properties" : { - "annotations" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - }, - "description" : "Internal api" - } - } - }, - "otoroshi.plugins.accesslog.AccessLog" : { - "description" : "Plugin that log access", - "type" : "object", - "properties" : { } - }, - "otoroshi.models.DataCenterMatch" : { - "description" : "Match a target if in the same datacenter", - "type" : "object", - "properties" : { - "type" : { - "description" : "the kind of predicate", - "type" : "string", - "enum" : [ "AlwaysMatch", "NetworkLocationMatch", "GeolocationMatch" ] - }, - "dc" : { - "description" : "DC name", - "type" : "string" - } - } - }, - "otoroshi.models.JwtTokenLocation" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/otoroshi.models.InCookie" - }, { - "$ref" : "#/components/schemas/otoroshi.models.InHeader" - }, { - "$ref" : "#/components/schemas/otoroshi.models.InQueryParam" - } ] - }, - "otoroshi.models.HSAlgoSettings" : { - "description" : "Settings to use HMAC-SHA signing algorithm", - "type" : "object", - "properties" : { - "size" : { - "format" : "int32", - "description" : "Size for SHA function", - "type" : "integer" - }, - "base64" : { - "description" : "The secret is base64 encoded", - "type" : "boolean" - }, - "secret" : { - "description" : "HMAC secret", - "type" : "string" - }, - "type" : { - "description" : "the kind of algosettings", - "type" : "string", - "enum" : [ "HSAlgoSettings", "RSAlgoSettings", "ESAlgoSettings", "JWKSAlgoSettings", "RSAKPAlgoSettings", "ESKPAlgoSettings", "KidAlgoSettings" ] - } - } - }, - "otoroshi.next.models.NgTarget" : { - "description" : "A target where incoming requests will be forwarded", - "type" : "object", - "properties" : { - "ip_address" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Null" - }, { - "type" : "string" - } ], - "description" : "Target ip address. Usefull to make manual DNS resolution without breaking SNI" - }, - "protocol" : { - "description" : "Protocol for the target", - "type" : "string", - "enum" : [ "HTTP/1.0", "HTTP/1.1", "HTTP/2.0" ] - }, - "predicate" : { - "description" : "Predicate to choose this target", - "$ref" : "#/components/schemas/otoroshi.models.TargetPredicate" - }, - "tls_config" : { - "description" : "TLS settings to contact this target", - "$ref" : "#/components/schemas/otoroshi.next.models.NgTlsConfig" - }, - "tls" : { - "description" : "Does the target uses TLS", - "type" : "boolean" - }, - "port" : { - "format" : "int32", - "description" : "port of the target", - "type" : "integer" - }, - "id" : { - "description" : "id of the target", - "type" : "string" - }, - "weight" : { - "format" : "int32", - "description" : "The weight of the target when choosing", - "type" : "integer" - }, - "hostname" : { - "description" : "hostname of the target", - "type" : "string" - } - } - }, - "otoroshi.models.UserAgentSettings" : { - "description" : "Settings to extract informations about user agent (for otoroshi events)", - "type" : "object", - "properties" : { - "enabled" : { - "description" : "User agent extraction enabled", - "type" : "boolean" - } - } - }, - "otoroshi.plugins.useragent.UserAgentHelper" : { - "description" : "Internal api", - "type" : "object", - "properties" : { } - }, - "otoroshi.next.plugins.NgApikeyCallsConfig" : { - "description" : "Configuration for ApikeyCalls", - "type" : "object", - "properties" : { - "extractors" : { - "description" : "Configuration of the apikey extraction modes", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyExtractors" - }, - "pass_with_user" : { - "description" : "Let the request pass if a user is connected", - "type" : "boolean" - }, - "wipe_backend_request" : { - "description" : "Removes the apikeys from the request to not forward it to the backend", - "type" : "boolean" - }, - "validate" : { - "description" : "Enabled quotas validation", - "type" : "boolean" - }, - "routing" : { - "description" : "Use apikey for routing", - "$ref" : "#/components/schemas/otoroshi.next.plugins.NgApikeyMatcher" - }, - "update_quotas" : { - "description" : "???", - "type" : "boolean" - } - } - } - }, - "securitySchemes" : { - "otoroshi_auth" : { - "type" : "http", - "scheme" : "basic" - } - } - } -} \ No newline at end of file diff --git a/docs/manual/code/swagger.json b/docs/manual/code/swagger.json deleted file mode 100644 index 457835c92d..0000000000 --- a/docs/manual/code/swagger.json +++ /dev/null @@ -1,8099 +0,0 @@ -{ - "openapi" : "3.0.0", - "info" : { - "version" : "1.5.0-dev", - "title" : "Otoroshi Admin API", - "description" : "Admin API of the Otoroshi reverse proxy", - "contact" : { - "name" : "Otoroshi Team", - "email" : "oss@maif.fr" - }, - "license" : { - "name" : "Apache 2.0", - "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "tags" : [ { - "name" : "configuration", - "description" : "Everything about Otoroshi global configuration" - }, { - "name" : "import", - "description" : "Everything about Otoroshi import/export" - }, { - "name" : "templates", - "description" : "Everything about Otoroshi entities templates" - }, { - "name" : "environments", - "description" : "Everything about Otoroshi Environments" - }, { - "name" : "groups", - "description" : "Everything about Otoroshi service groups" - }, { - "name" : "apikeys", - "description" : "Everything about Otoroshi api keys" - }, { - "name" : "services", - "description" : "Everything about Otoroshi service descriptors" - }, { - "name" : "stats", - "description" : "Everything about Otoroshi stats" - }, { - "name" : "snowmonkey", - "description" : "Everything about Otoroshi Snow Monkey" - }, { - "name" : "health", - "description" : "Everything about Otoroshi health status" - }, { - "name" : "jwt-verifiers", - "description" : "Everything about Otoroshi global JWT token verifiers" - }, { - "name" : "auth-config", - "description" : "Everything about Otoroshi global auth. module config" - }, { - "name" : "scripts", - "description" : "Everything about Otoroshi request transformer scripts" - }, { - "name" : "certificates", - "description" : "Everything about Otoroshi SSL/TLS certificates" - }, { - "name" : "validation-authorities", - "description" : "Everything about Otoroshi validation authorities" - }, { - "name" : "data-exporter-configs", - "description" : "Everything about Otoroshi data exporters" - } ], - "externalDocs" : { - "description" : "Find out more about Otoroshi", - "url" : "https://maif.github.io/otoroshi/" - }, - "servers" : [ { - "url" : "http://otoroshi-api.oto.tools/" - } ], - "paths" : { - "/new/apikey" : { - "get" : { - "deprecated" : false, - "tags" : [ "templates" ], - "summary" : "Get a template of an Otoroshi Api Key", - "description" : "Get a template of an Otoroshi Api Key. The generated entity is not persisted", - "operationId" : "initiateApiKey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/new/service" : { - "get" : { - "deprecated" : false, - "tags" : [ "templates" ], - "summary" : "Get a template of an Otoroshi service descriptor", - "description" : "Get a template of an Otoroshi service descriptor. The generated entity is not persisted", - "operationId" : "initiateService", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/new/group" : { - "get" : { - "deprecated" : false, - "tags" : [ "templates" ], - "summary" : "Get a template of an Otoroshi service group", - "description" : "Get a template of an Otoroshi service group. The generated entity is not persisted", - "operationId" : "initiateServiceGroup", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/lines" : { - "get" : { - "deprecated" : false, - "tags" : [ "environments" ], - "summary" : "Get all environments", - "description" : "Get all environments provided by the current Otoroshi instance", - "operationId" : "allLines", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Environment" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/lines/{line}/services" : { - "get" : { - "deprecated" : false, - "tags" : [ "environments" ], - "summary" : "Get all services for an environment", - "description" : "Get all services for an environment provided by the current Otoroshi instance", - "operationId" : "servicesForALine", - "parameters" : [ { - "in" : "path", - "name" : "line", - "required" : true, - "description" : "The environment where to find services", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/apikeys/{clientId}/quotas" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get the quota state of an api key", - "description" : "Get the quota state of an api key", - "operationId" : "apiKeyQuotas", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Quotas" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Reset the quota state of an api key", - "description" : "Reset the quota state of an api key", - "operationId" : "resetApiKeyQuotas", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Quotas" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/apikeys/{clientId}/group" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get the group of an api key", - "description" : "Get the group of an api key", - "operationId" : "apiKeyGroup", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/apikeys/{clientId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get an api key", - "description" : "Get an api key for a specified service descriptor", - "operationId" : "apiKey", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Update an api key", - "description" : "Update an api key for a specified service descriptor", - "operationId" : "updateApiKey", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Update an api key with a diff", - "description" : "Update an api key for a specified service descriptor with a diff", - "operationId" : "patchApiKey", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Delete an api key", - "description" : "Delete an api key for a specified service descriptor", - "operationId" : "deleteApiKey", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/apikeys" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get all api keys for the group of a service", - "description" : "Get all api keys for the group of a service", - "operationId" : "apiKeys", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Create a new api key for a service", - "description" : "", - "operationId" : "createApiKey", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The api key service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "/api/groups/{groupId}/apikeys/{clientId}/quotas" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get the quota state of an api key", - "description" : "Get the quota state of an api key", - "operationId" : "apiKeyFromGroupQuotas", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Quotas" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Reset the quota state of an api key", - "description" : "Reset the quota state of an api key", - "operationId" : "resetApiKeyFromGroupQuotas", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Quotas" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/groups/{groupId}/apikeys/{clientId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get an api key", - "description" : "Get an api key for a specified service group", - "operationId" : "apiKeyFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Update an api key", - "description" : "Update an api key for a specified service group", - "operationId" : "updateApiKeyFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Update an api key with a diff", - "description" : "Update an api key for a specified service descriptor with a diff", - "operationId" : "patchApiKeyFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Delete an api key", - "description" : "Delete an api key for a specified service group", - "operationId" : "deleteApiKeyFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - }, { - "in" : "path", - "name" : "clientId", - "required" : true, - "description" : "the api key id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/groups/{groupId}/apikeys" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get all api keys for the group of a service", - "description" : "Get all api keys for the group of a service", - "operationId" : "apiKeysFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Create a new api key for a group", - "description" : "Create a new api key for a group", - "operationId" : "createApiKeyFromGroup", - "parameters" : [ { - "in" : "path", - "name" : "groupId", - "required" : true, - "description" : "The api key group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "/api/apikeys" : { - "get" : { - "deprecated" : false, - "tags" : [ "apikeys" ], - "summary" : "Get all api keys", - "description" : "Get all api keys", - "operationId" : "allApiKeys", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/template" : { - "get" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Get a service descriptor error template", - "description" : "Get a service descriptor error template", - "operationId" : "serviceTemplate", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Update an error template to a service descriptor", - "description" : "Update an error template to a service descriptor", - "operationId" : "updateServiceTemplate", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplate" - } - } - } - } - }, - "post" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Create a service descriptor error template", - "description" : "Update a service descriptor targets", - "operationId" : "createServiceTemplate", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorTemplate" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Delete a service descriptor error template", - "description" : "Delete a service descriptor error template", - "operationId" : "deleteServiceTemplate", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}/targets" : { - "get" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Get a service descriptor targets", - "description" : "Get a service descriptor targets", - "operationId" : "serviceTargets", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Add a target to a service descriptor", - "description" : "Add a target to a service descriptor", - "operationId" : "serviceAddTarget", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Target" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Update a service descriptor targets", - "description" : "Update a service descriptor targets", - "operationId" : "updateServiceTargets", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Delete a service descriptor target", - "description" : "Delete a service descriptor target", - "operationId" : "serviceDeleteTarget", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services/{serviceId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Get a service descriptor", - "description" : "Get a service descriptor", - "operationId" : "service", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Update a service descriptor", - "description" : "Update a service descriptor", - "operationId" : "updateService", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Update a service descriptor with a diff", - "description" : "Update a service descriptor with a diff", - "operationId" : "patchService", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Delete a service descriptor", - "description" : "Delete a service descriptor", - "operationId" : "deleteService", - "parameters" : [ { - "in" : "path", - "name" : "serviceId", - "required" : true, - "description" : "The service id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/services" : { - "get" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Get all services", - "description" : "Get all services", - "operationId" : "allServices", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Create a new service descriptor", - "description" : "Create a new service descriptor", - "operationId" : "createService", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Service" - } - } - } - } - } - }, - "/api/groups/{serviceGroupId}/services" : { - "get" : { - "deprecated" : false, - "tags" : [ "services" ], - "summary" : "Get all services descriptor for a group", - "description" : "Get all services descriptor for a group", - "operationId" : "serviceGroupServices", - "parameters" : [ { - "in" : "path", - "name" : "serviceGroupId", - "required" : true, - "description" : "The service group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ApiKey" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/groups/{serviceGroupId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Get a service group", - "description" : "Get a service group", - "operationId" : "serviceGroup", - "parameters" : [ { - "in" : "path", - "name" : "serviceGroupId", - "required" : true, - "description" : "The service group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Update a service group", - "description" : "Update a service group", - "operationId" : "updateGroup", - "parameters" : [ { - "in" : "path", - "name" : "serviceGroupId", - "required" : true, - "description" : "The service group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Update a service group with a diff", - "description" : "Update a service group with a diff", - "operationId" : "patchGroup", - "parameters" : [ { - "in" : "path", - "name" : "serviceGroupId", - "required" : true, - "description" : "The service group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Delete a service group", - "description" : "Delete a service group", - "operationId" : "deleteGroup", - "parameters" : [ { - "in" : "path", - "name" : "serviceGroupId", - "required" : true, - "description" : "The service group id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/groups" : { - "get" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Get all service groups", - "description" : "Get all service groups", - "operationId" : "allServiceGroups", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "groups" ], - "summary" : "Create a new service group", - "description" : "Create a new service group", - "operationId" : "createGroup", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - } - }, - "/api/verifiers" : { - "get" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Get all global JWT verifiers", - "description" : "Get all global JWT verifiers", - "operationId" : "findAllGlobalJwtVerifiers", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Create one global JWT verifiers", - "description" : "Create one global JWT verifiers", - "operationId" : "createGlobalJwtVerifier", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - } - }, - "/api/verifiers/{verifierId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Get one global JWT verifiers", - "description" : "Get one global JWT verifiers", - "operationId" : "findGlobalJwtVerifiersById", - "parameters" : [ { - "in" : "path", - "name" : "verifierId", - "required" : true, - "description" : "The jwt verifier id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Delete one global JWT verifiers", - "description" : "Delete one global JWT verifiers", - "operationId" : "deleteGlobalJwtVerifier", - "parameters" : [ { - "in" : "path", - "name" : "verifierId", - "required" : true, - "description" : "The jwt verifier id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Update one global JWT verifiers", - "description" : "Update one global JWT verifiers", - "operationId" : "updateGlobalJwtVerifier", - "parameters" : [ { - "in" : "path", - "name" : "verifierId", - "required" : true, - "description" : "The jwt verifier id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "jwt-verifiers" ], - "summary" : "Update one global JWT verifiers", - "description" : "Update one global JWT verifiers", - "operationId" : "patchGlobalJwtVerifier", - "parameters" : [ { - "in" : "path", - "name" : "verifierId", - "required" : true, - "description" : "The jwt verifier id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalJwtVerifier" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/auths" : { - "get" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Get all global auth. module configs", - "description" : "Get all global auth. module configs", - "operationId" : "findAllGlobalAuthModules", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Create one global auth. module config", - "description" : "Create one global auth. module config", - "operationId" : "createGlobalAuthModule", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - } - }, - "/api/auths/{id}" : { - "get" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Get one global auth. module configs", - "description" : "Get one global auth. module configs", - "operationId" : "findGlobalAuthModuleById", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Delete one global auth. module config", - "description" : "Delete one global auth. module config", - "operationId" : "deleteGlobalAuthModule", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Update one global auth. module config", - "description" : "Update one global auth. module config", - "operationId" : "updateGlobalAuthModule", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "auth-config" ], - "summary" : "Update one global auth. module config", - "description" : "Update one global auth. module config", - "operationId" : "patchGlobalAuthModule", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LdapAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/InMemoryAuthModuleConfig" - }, { - "$ref" : "#/components/schemas/GenericOauth2ModuleConfig" - } ] - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/scripts/_compile" : { - "post" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Compile a script", - "description" : "Compile a script", - "operationId" : "compileScript", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ScriptCompilationResult" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - } - }, - "/api/scripts/{scriptId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Get a script", - "description" : "Get a script", - "operationId" : "findScriptById", - "parameters" : [ { - "in" : "path", - "name" : "scriptId", - "required" : true, - "description" : "The script id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Update a script", - "description" : "Update a script", - "operationId" : "updateScript", - "parameters" : [ { - "in" : "path", - "name" : "scriptId", - "required" : true, - "description" : "The script id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Update a script with a diff", - "description" : "Update a script with a diff", - "operationId" : "patchScript", - "parameters" : [ { - "in" : "path", - "name" : "scriptId", - "required" : true, - "description" : "The script id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Delete a script", - "description" : "Delete a script", - "operationId" : "deleteScript", - "parameters" : [ { - "in" : "path", - "name" : "scriptId", - "required" : true, - "description" : "The script id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/scripts" : { - "get" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Get all scripts", - "description" : "Get all scripts", - "operationId" : "findAllScripts", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "scripts" ], - "summary" : "Create a new script", - "description" : "Create a new script", - "operationId" : "createScript", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Script" - } - } - } - } - } - }, - "/api/data-exporter-configs/_template" : { - "get" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Get all data exporter configs", - "description" : "Get all data exporter configs", - "operationId" : "DataExporterTemplate", - "parameters" : [ { - "in" : "query", - "name" : "type", - "required" : false, - "description" : "The data exporter config type", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/data-exporter-configs/_bulk" : { - "post" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Create a new data exporter configs", - "description" : "Create a new data exporter configs", - "operationId" : "createBulkDataExporterConfigs", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "description" : "The bulk response", - "type" : "object", - "properties" : { - "status" : { - "type" : "string", - "enum" : [ "201" ], - "description" : "Status" - }, - "created" : { - "type" : "boolean", - "example" : true, - "description" : "Whether the action was carried out correctly or not" - }, - "id" : { - "type" : "boolean", - "example" : true, - "description" : "Data exporter id" - } - } - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "put" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Update a data exporter configs", - "description" : "Update a data exporter configs", - "operationId" : "updateBulkDataExporterConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "description" : "The bulk response", - "type" : "object", - "properties" : { - "status" : { - "type" : "string", - "enum" : [ "200" ], - "description" : "Status" - }, - "updated" : { - "type" : "boolean", - "example" : true, - "description" : "Whether the action was carried out correctly or not" - }, - "id" : { - "type" : "boolean", - "example" : true, - "description" : "Data exporter id" - } - } - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Update a data exporter configs with a diff", - "description" : "Update a data exporter configs with a diff", - "operationId" : "patchBulkDataExporterConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "description" : "The bulk response", - "type" : "object", - "properties" : { - "status" : { - "type" : "string", - "enum" : [ "200" ], - "description" : "Status" - }, - "updated" : { - "type" : "boolean", - "example" : true, - "description" : "Whether the action was carried out correctly or not" - }, - "id" : { - "type" : "boolean", - "example" : true, - "description" : "Data exporter id" - } - } - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Delete a data exporter config", - "description" : "Delete a data exporter config", - "operationId" : "deletebulkDataExporterConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "description" : "The bulk response", - "type" : "object", - "properties" : { - "status" : { - "type" : "string", - "enum" : [ "200" ], - "description" : "Status" - }, - "deleted" : { - "type" : "boolean", - "example" : true, - "description" : "Whether the action was carried out correctly or not" - }, - "id" : { - "type" : "boolean", - "example" : true, - "description" : "Data exporter id" - } - } - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/ndjson" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/data-exporter-configs/{dataExporterConfigId}" : { - "get" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Get a data exporter config", - "description" : "Get a data exporter config", - "operationId" : "findDataExporterConfigById", - "parameters" : [ { - "in" : "path", - "name" : "dataExporterConfigId", - "required" : true, - "description" : "The data exporter config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Update a data exporter config", - "description" : "Update a data exporter config", - "operationId" : "updateDataExporterConfig", - "parameters" : [ { - "in" : "path", - "name" : "dataExporterConfigId", - "required" : true, - "description" : "The data exporter config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Update a data exporter config with a diff", - "description" : "Update a data exporter config with a diff", - "operationId" : "patchDataExporterConfig", - "parameters" : [ { - "in" : "path", - "name" : "dataExporterConfigId", - "required" : true, - "description" : "The data exporter config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - }, - "delete" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Delete a data exporter config", - "description" : "Delete a data exporter config", - "operationId" : "deleteDataExporterConfig", - "parameters" : [ { - "in" : "path", - "name" : "dataExporterConfigId", - "required" : true, - "description" : "The data exporter config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/data-exporter-configs" : { - "get" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Get all data exporter configs", - "description" : "Get all data exporter configs", - "operationId" : "findAllDataExporters", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "data-exporter-configs" ], - "summary" : "Create a new data exporter config", - "description" : "Create a new data exporter config", - "operationId" : "createDataExporterConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/DataExporterConfig" - } - } - } - } - } - }, - "/api/certificates" : { - "get" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Get all certificates", - "description" : "Get all certificates", - "operationId" : "allCerts", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Create one certificate", - "description" : "Create one certificate", - "operationId" : "createCert", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - } - }, - "/api/certificates/{id}" : { - "get" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Get one certificate by id", - "description" : "Get one certificate by id", - "operationId" : "oneCert", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Delete one certificate by id", - "description" : "Delete one certificate by id", - "operationId" : "deleteCert", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The certificate id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Update one certificate by id", - "description" : "Update one certificate by id", - "operationId" : "putCert", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The certificate id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "certificates" ], - "summary" : "Update one certificate by id", - "description" : "Update one certificate by id", - "operationId" : "patchCert", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The certificate id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Certificate" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/client-validators" : { - "get" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Get all validation authoritiess", - "description" : "Get all validation authoritiess", - "operationId" : "findAllClientValidators", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Create one validation authorities", - "description" : "Create one validation authorities", - "operationId" : "createClientValidator", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - } - }, - "/api/client-validators/{id}" : { - "get" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Get one validation authorities by id", - "description" : "Get one validation authorities by id", - "operationId" : "findClientValidatorById", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The auth. config id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Delete one validation authorities by id", - "description" : "Delete one validation authorities by id", - "operationId" : "deleteClientValidator", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The validation authorities id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Deleted" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Update one validation authorities by id", - "description" : "Update one validation authorities by id", - "operationId" : "updateClientValidator", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The validation authorities id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "validation-authorities" ], - "summary" : "Update one validation authorities by id", - "description" : "Update one validation authorities by id", - "operationId" : "patchClientValidator", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The validation authorities id", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ValidationAuthority" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/snowmonkey/config" : { - "get" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Get current Snow Monkey config", - "description" : "Get current Snow Monkey config", - "operationId" : "getSnowMonkeyConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SnowMonkeyConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Update current Snow Monkey config", - "description" : "Update current Snow Monkey config", - "operationId" : "updateSnowMonkey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SnowMonkeyConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Update current Snow Monkey config", - "description" : "Update current Snow Monkey config", - "operationId" : "patchSnowMonkey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SnowMonkeyConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Group" - } - } - } - } - } - }, - "/api/snowmonkey/outages" : { - "get" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Get all current Snow Monkey ourages", - "description" : "Get all current Snow Monkey ourages", - "operationId" : "getSnowMonkeyOutages", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Outage" - } - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "delete" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Reset Snow Monkey Outages for the day", - "description" : "Reset Snow Monkey Outages for the day", - "operationId" : "resetSnowMonkey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/snowmonkey/_start" : { - "post" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Start the Snow Monkey", - "description" : "Start the Snow Monkey", - "operationId" : "startSnowMonkey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/snowmonkey/_stop" : { - "post" : { - "deprecated" : false, - "tags" : [ "snowmonkey" ], - "summary" : "Stop the Snow Monkey", - "description" : "Stop the Snow Monkey", - "operationId" : "stopSnowMonkey", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/live/{id}" : { - "get" : { - "deprecated" : false, - "tags" : [ "stats" ], - "summary" : "Get live feed of otoroshi stats", - "description" : "Get live feed of global otoroshi stats (global) or for a service {id}", - "operationId" : "serviceLiveStats", - "parameters" : [ { - "in" : "path", - "name" : "id", - "required" : true, - "description" : "The service id or global for otoroshi stats", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Stats" - } - }, - "text/event-stream" : { - "schema" : { - "$ref" : "#/components/schemas/Stats" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/live" : { - "get" : { - "deprecated" : false, - "tags" : [ "stats" ], - "summary" : "Get global otoroshi stats", - "description" : "Get global otoroshi stats", - "operationId" : "globalLiveStats", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Stats" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - } - }, - "/api/globalconfig" : { - "get" : { - "deprecated" : false, - "tags" : [ "configuration" ], - "summary" : "Get the full configuration of Otoroshi", - "description" : "Get the full configuration of Otoroshi", - "operationId" : "globalConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "put" : { - "deprecated" : false, - "tags" : [ "configuration" ], - "summary" : "Update the global configuration", - "description" : "Update the global configuration", - "operationId" : "putGlobalConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfig" - } - } - } - } - }, - "patch" : { - "deprecated" : false, - "tags" : [ "configuration" ], - "summary" : "Update the global configuration with a diff", - "description" : "Update the global configuration with a diff", - "operationId" : "patchGlobalConfig", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GlobalConfig" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Patch" - } - } - } - } - } - }, - "/api/otoroshi.json" : { - "get" : { - "deprecated" : false, - "tags" : [ "import" ], - "summary" : "Export the full state of Otoroshi", - "description" : "Export the full state of Otoroshi", - "operationId" : "fullExport", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ImportExport" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ] - }, - "post" : { - "deprecated" : false, - "tags" : [ "import" ], - "summary" : "Import the full state of Otoroshi", - "description" : "Import the full state of Otoroshi", - "operationId" : "fullImport", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ImportExport" - } - } - } - } - } - }, - "/api/import" : { - "post" : { - "deprecated" : false, - "tags" : [ "import" ], - "summary" : "Import the full state of Otoroshi as a file", - "description" : "Import the full state of Otoroshi as a file", - "operationId" : "fullImportFromFile", - "parameters" : [ ], - "responses" : { - "401" : { - "description" : "You have to provide an Api Key. Api Key can be passed with 'Otoroshi-Client-Id' and 'Otoroshi-Client-Secret' headers, or use basic http authentication" - }, - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Done" - } - } - } - } - }, - "security" : [ { - "otoroshi_auth" : [ ] - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ImportExport" - } - } - } - } - } - }, - "/health" : { - "get" : { - "deprecated" : false, - "tags" : [ "health" ], - "summary" : "Return current Otoroshi health", - "description" : "Import the full state of Otoroshi as a file", - "operationId" : "health", - "parameters" : [ ], - "responses" : { - "400" : { - "description" : "Bad resource format. Take another look to the swagger, or open an issue :)" - }, - "404" : { - "description" : "Resource not found or does not exist" - }, - "200" : { - "description" : "Successful operation", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/OtoroshiHealth" - } - } - } - } - } - } - } - }, - "components" : { - "securitySchemes" : { - "otoroshi_auth" : { - "type" : "http", - "scheme" : "basic" - } - }, - "schemas" : { - "ApiKey" : { - "description" : "An Otoroshi Api Key. An Api Key is defined for a group of services to allow usage of the same Api Key for multiple services.", - "type" : "object", - "required" : [ "clientId", "clientSecret", "clientName", "authorizedEntities", "enabled" ], - "properties" : { - "clientId" : { - "type" : "string", - "example" : "a string value", - "description" : "The unique id of the Api Key. Usually 16 random alpha numerical characters, but can be anything" - }, - "clientSecret" : { - "type" : "string", - "example" : "a string value", - "description" : "The secret of the Api Key. Usually 64 random alpha numerical characters, but can be anything" - }, - "clientName" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the api key, for humans ;-)" - }, - "authorizedEntities" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "example" : [ "a string value" ], - "description" : "The group/service ids (prefixed by group_ or service_ on which the key is authorized" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not the key is enabled. If disabled, resources won't be available to calls using this key" - }, - "throttlingQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per second, measured on 10 seconds" - }, - "dailyQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per day" - }, - "monthlyQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per month" - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Bunch of metadata for the key" - } - } - }, - "Auth0Config" : { - "description" : "Configuration for Auth0 domain", - "type" : "object", - "required" : [ "clientId", "clientSecret", "domain", "callbackUrl" ], - "properties" : { - "clientId" : { - "type" : "string", - "example" : "a string value", - "description" : "Auth0 client id" - }, - "clientSecret" : { - "type" : "string", - "example" : "a string value", - "description" : "Auth0 client secret" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "Auth0 domain" - }, - "callbackUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "Auth0 callback URL" - } - } - }, - "Canary" : { - "description" : "The configuration of the canary mode for a service descriptor", - "type" : "object", - "required" : [ "enabled", "traffic", "targets", "root" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Use canary mode for this service" - }, - "traffic" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Ratio of traffic that will be sent to canary targets." - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - }, - "description" : "The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures" - }, - "root" : { - "type" : "string", - "example" : "a string value", - "description" : "Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar" - } - } - }, - "CleverSettings" : { - "description" : "Configuration for CleverCloud client", - "type" : "object", - "required" : [ "consumerKey", "consumerSecret", "token", "secret", "orgaId" ], - "properties" : { - "consumerKey" : { - "type" : "string", - "example" : "a string value", - "description" : "CleverCloud consumer key" - }, - "consumerSecret" : { - "type" : "string", - "example" : "a string value", - "description" : "CleverCloud consumer token" - }, - "token" : { - "type" : "string", - "example" : "a string value", - "description" : "CleverCloud oauth token" - }, - "secret" : { - "type" : "string", - "example" : "a string value", - "description" : "CleverCloud oauth secret" - }, - "orgaId" : { - "type" : "string", - "example" : "a string value", - "description" : "CleverCloud organization id" - } - } - }, - "ClientConfig" : { - "description" : "The configuration of the circuit breaker for a service descriptor", - "type" : "object", - "required" : [ "useCircuitBreaker", "retries", "maxErrors", "retryInitialDelay", "backoffFactor", "callTimeout", "globalTimeout", "sampleInterval" ], - "properties" : { - "useCircuitBreaker" : { - "type" : "boolean", - "example" : true, - "description" : "Use a circuit breaker to avoid cascading failure when calling chains of services. Highly recommended !" - }, - "retries" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify how many times the client will try to fetch the result of the request after an error before giving up." - }, - "maxErrors" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify how many errors can pass before opening the circuit breaker" - }, - "retryInitialDelay" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor" - }, - "backoffFactor" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify the factor to multiply the delay for each retry" - }, - "callTimeout" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify how long each call should last at most in milliseconds" - }, - "globalTimeout" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify how long the global call (with retries) should last at most in milliseconds" - }, - "sampleInterval" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted" - } - } - }, - "Deleted" : { - "type" : "object", - "required" : [ "deleted" ], - "properties" : { - "deleted" : { - "type" : "boolean", - "example" : true - } - } - }, - "Done" : { - "type" : "object", - "required" : [ "done" ], - "properties" : { - "done" : { - "type" : "boolean", - "example" : true - } - } - }, - "Environment" : { - "type" : "string", - "example" : "prod", - "description" : "The name of the environment for service descriptors" - }, - "ErrorTemplate" : { - "description" : "Error templates for a service descriptor", - "type" : "object", - "required" : [ "serviceId", "template40x", "template50x", "templateBuild", "templateMaintenance", "messages" ], - "properties" : { - "serviceId" : { - "type" : "string", - "example" : "a string value", - "description" : "The Id of the service for which the error template is enabled" - }, - "template40x" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for 40x errors" - }, - "template50x" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for 50x errors" - }, - "templateBuild" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for build page" - }, - "templateMaintenance" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for maintenance page" - }, - "messages" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Map for custom messages" - } - } - }, - "ExposedApi" : { - "description" : "The Open API configuration for your service (if one)", - "type" : "object", - "required" : [ "exposeApi" ], - "properties" : { - "exposeApi" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not the current service expose an API with an Open API descriptor" - }, - "openApiDescriptorUrl" : { - "type" : "string", - "format" : "uri", - "example" : "http://www.google.com", - "description" : "The URL of the Open API descriptor" - } - } - }, - "GlobalConfig" : { - "type" : "object", - "required" : [ "streamEntityOnly", "autoLinkToDefaultGroup", "limitConcurrentRequests", "maxConcurrentRequests", "useCircuitBreakers", "apiReadOnly", "u2fLoginOnly", "ipFiltering", "throttlingQuota", "perIpThrottlingQuota", "analyticsWebhooks", "alertsWebhooks", "alertsEmails", "endlessIpAddresses" ], - "description" : "The global config object of Otoroshi, used to customize settings of the current Otoroshi instance", - "properties" : { - "lines" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Possibles lines for Otoroshi" - }, - "streamEntityOnly" : { - "type" : "boolean", - "example" : true, - "description" : "HTTP will be streamed only. Doesn't work with old browsers" - }, - "autoLinkToDefaultGroup" : { - "type" : "boolean", - "example" : true, - "description" : "If not defined, every new service descriptor will be added to the default group" - }, - "limitConcurrentRequests" : { - "type" : "boolean", - "example" : true, - "description" : "If enabled, Otoroshi will reject new request if too much at the same time" - }, - "maxConcurrentRequests" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of authorized request processed at the same time" - }, - "maxHttp10ResponseSize" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The max size in bytes of an HTTP 1.0 response" - }, - "useCircuitBreakers" : { - "type" : "boolean", - "example" : true, - "description" : "If enabled, services will be authorized to use circuit breakers" - }, - "apiReadOnly" : { - "type" : "boolean", - "example" : true, - "description" : "If enabled, Admin API won't be able to write/update/delete entities" - }, - "u2fLoginOnly" : { - "type" : "boolean", - "example" : true, - "description" : "If enabled, login to backoffice through Auth0 will be disabled" - }, - "ipFiltering" : { - "$ref" : "#/components/schemas/IpFiltering" - }, - "throttlingQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per second globally, measured on 10 seconds" - }, - "perIpThrottlingQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per second globally per IP address, measured on 10 seconds" - }, - "elasticWritesConfigs" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ElasticConfig" - }, - "description" : "Configs. for Elastic writes" - }, - "elasticReadsConfig" : { - "$ref" : "#/components/schemas/ElasticConfig", - "description" : "Config. for elastic reads" - }, - "analyticsWebhooks" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Webhook" - }, - "description" : "Webhook that will receive all internal Otoroshi events" - }, - "alertsWebhooks" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Webhook" - }, - "description" : "Webhook that will receive all Otoroshi alert events" - }, - "alertsEmails" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "email", - "example" : "admin@otoroshi.io" - }, - "description" : "Email addresses that will receive all Otoroshi alert events" - }, - "endlessIpAddresses" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "ipv4", - "example" : "192.192.192.192" - }, - "description" : "IP addresses for which any request to Otoroshi will respond with 128 Gb of zeros" - }, - "middleFingers" : { - "type" : "boolean", - "example" : true, - "description" : "Use middle finger emoji as a response character for endless HTTP responses" - }, - "maxLogsSize" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Number of events kept locally" - }, - "cleverSettings" : { - "$ref" : "#/components/schemas/CleverSettings", - "description" : "Optional CleverCloud configuration" - }, - "mailerSettings" : { - "$ref" : "#/components/schemas/MailerSettings", - "description" : "Optional mailer configuration" - }, - "backofficeAuth0Config" : { - "$ref" : "#/components/schemas/Auth0Config", - "description" : "Optional configuration for the backoffice Auth0 domain" - }, - "privateAppsAuth0Config" : { - "$ref" : "#/components/schemas/Auth0Config", - "description" : "Optional configuration for the private apps Auth0 domain" - } - } - }, - "Group" : { - "description" : "An Otoroshi service group is just a group of service descriptor. It is useful to be able to define Api Keys for the whole group", - "type" : "object", - "required" : [ "id", "name" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "The unique id of the group. Usually 64 random alpha numerical characters, but can be anything" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the group" - }, - "description" : { - "type" : "string", - "example" : "a string value", - "description" : "The descriptoin of the group" - } - } - }, - "HealthCheck" : { - "description" : "The configuration for checking health of a service. Otoroshi will perform GET call on the URL to check if the service is still alive", - "type" : "object", - "required" : [ "enabled" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not healthcheck is enabled on the current service descriptor" - }, - "url" : { - "type" : "string", - "format" : "uri", - "example" : "http://www.google.com", - "description" : "The URL to check" - } - } - }, - "OtoroshiHealth" : { - "description" : "The structure that represent current Otoroshi health", - "type" : "object", - "required" : [ "label", "otoroshi", "datastore" ], - "properties" : { - "otoroshi" : { - "type" : "string", - "enum" : [ "healthy", "unhealthy", "down" ] - }, - "datastore" : { - "type" : "string", - "enum" : [ "healthy", "unhealthy", "unreachable" ] - } - } - }, - "ImportExport" : { - "description" : "The structure that can be imported to or exported from Otoroshi. It represent the memory state of Otoroshi", - "type" : "object", - "required" : [ "label", "dateRaw", "date", "stats", "config", "admins", "simpleAdmins", "serviceGroups", "apiKeys", "serviceDescriptors", "errorTemplates" ], - "properties" : { - "label" : { - "type" : "string", - "example" : "a string value" - }, - "dateRaw" : { - "type" : "integer", - "format" : "int64", - "example" : 123 - }, - "date" : { - "type" : "string", - "format" : "date-time", - "example" : "2017-07-21T17:32:28Z" - }, - "stats" : { - "$ref" : "#/components/schemas/ImportExportStats", - "description" : "Current global stats at the time of export" - }, - "config" : { - "$ref" : "#/components/schemas/GlobalConfig", - "description" : "Current global config at the time of export" - }, - "appConfig" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Current env variables at the time of export" - }, - "admins" : { - "type" : "array", - "items" : { - "description" : "Administrator using FIDO U2F device to access Otoroshi", - "type" : "object", - "required" : [ "username", "label", "password", "createdAt", "registration" ], - "properties" : { - "username" : { - "type" : "string", - "example" : "a string value", - "description" : "The email address of the user" - }, - "label" : { - "type" : "string", - "example" : "a string value", - "description" : "The label for the user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "The hashed password of the user" - }, - "createdAt" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The creation date of the user" - }, - "registration" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The U2F registration slug" - } - } - }, - "description" : "Current U2F admin at the time of export" - }, - "simpleAdmins" : { - "type" : "array", - "items" : { - "description" : "Administrator using just login/password tuple to access Otoroshi", - "type" : "object", - "required" : [ "username", "label", "password", "createdAt" ], - "properties" : { - "username" : { - "type" : "string", - "example" : "a string value", - "description" : "The email address of the user" - }, - "label" : { - "type" : "string", - "example" : "a string value", - "description" : "The label for the user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "The hashed password of the user" - }, - "createdAt" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The creation date of the user" - } - } - }, - "description" : "Current simple admins at the time of export" - }, - "serviceGroups" : { - "type" : "array", - "items" : { - "description" : "An Otoroshi service group is just a group of service descriptor. It is useful to be able to define Api Keys for the whole group", - "type" : "object", - "required" : [ "id", "name" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "The unique id of the group. Usually 64 random alpha numerical characters, but can be anything" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the group" - }, - "description" : { - "type" : "string", - "example" : "a string value", - "description" : "The descriptoin of the group" - } - } - }, - "description" : "Current service groups at the time of export" - }, - "apiKeys" : { - "type" : "array", - "items" : { - "description" : "An Otoroshi Api Key. An Api Key is defined for a group of services to allow usage of the same Api Key for multiple services.", - "type" : "object", - "required" : [ "clientId", "clientSecret", "clientName", "authorizedEntities", "enabled" ], - "properties" : { - "clientId" : { - "type" : "string", - "example" : "a string value", - "description" : "The unique id of the Api Key. Usually 16 random alpha numerical characters, but can be anything" - }, - "clientSecret" : { - "type" : "string", - "example" : "a string value", - "description" : "The secret of the Api Key. Usually 64 random alpha numerical characters, but can be anything" - }, - "clientName" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the api key, for humans ;-)" - }, - "authorizedEntities" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "example" : [ "a string value" ], - "description" : "The group/service ids (prefixed by group_ or service_ on which the key is authorized" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not the key is enabled. If disabled, resources won't be available to calls using this key" - }, - "throttlingQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per second, measured on 10 seconds" - }, - "dailyQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per day" - }, - "monthlyQuota" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Authorized number of calls per month" - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Bunch of metadata for the key" - } - } - }, - "description" : "Current apik keys at the time of export" - }, - "serviceDescriptors" : { - "type" : "array", - "items" : { - "description" : "An otoroshi service descriptor. Represent a forward HTTP call on a domain to another location with some optional api management mecanism", - "type" : "object", - "required" : [ "id", "groups", "name", "env", "domain", "subdomain", "targets", "root", "enabled", "privateApp", "forceHttps", "maintenanceMode", "buildMode", "enforceSecureCommunication" ], - "properties" : { - "id" : { - "type" : "string", - "format" : "uuid", - "example" : "110e8400-e29b-11d4-a716-446655440000", - "description" : "A unique random string to identify your service" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "example" : [ "a string value" ], - "description" : "Each service descriptor is attached to groups. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of your service. Only for debug and human readability purposes" - }, - "env" : { - "type" : "string", - "example" : "a string value", - "description" : "The line on which the service is available. Based on that value, the name of the line will be appended to the subdomain. For line prod, nothing will be appended. For example, if the subdomain is 'foo' and line is 'preprod', then the exposed service will be available at 'foo.preprod.mydomain'" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "The domain on which the service is available." - }, - "subdomain" : { - "type" : "string", - "example" : "a string value", - "description" : "The subdomain on which the service is available" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - }, - "description" : "The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures" - }, - "root" : { - "type" : "string", - "example" : "a string value", - "description" : "Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar" - }, - "matchingRoot" : { - "type" : "string", - "example" : "a string value", - "description" : "The root path on which the service is available" - }, - "localHost" : { - "type" : "string", - "example" : "a string value", - "description" : "The host used localy, mainly localhost:xxxx" - }, - "localScheme" : { - "type" : "string", - "example" : "a string value", - "description" : "The scheme used localy, mainly http" - }, - "redirectToLocal" : { - "type" : "boolean", - "example" : true, - "description" : "If you work locally with Otoroshi, you may want to use that feature to redirect one particuliar service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist" - }, - "userFacing" : { - "type" : "boolean", - "example" : true, - "description" : "The fact that this service will be seen by users and cannot be impacted by the Snow Monkey" - }, - "privateApp" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, user will be allowed to use the service (UI) only if they are registered users of the private apps domain" - }, - "forceHttps" : { - "type" : "boolean", - "example" : true, - "description" : "Will force redirection to https:// if not present" - }, - "maintenanceMode" : { - "type" : "boolean", - "example" : true, - "description" : "Display a maintainance page when a user try to use the service" - }, - "buildMode" : { - "type" : "boolean", - "example" : true, - "description" : "Display a construction page when a user try to use the service" - }, - "enforceSecureCommunication" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, Otoroshi will try to exchange headers with downstream service to ensure no one else can use the service from outside" - }, - "sendOtoroshiHeadersBack" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc ..." - }, - "xForwardedHeaders" : { - "type" : "boolean", - "example" : true, - "description" : "Send X-Forwarded-* headers" - }, - "overrideHost" : { - "type" : "boolean", - "example" : true, - "description" : "Host header will be overriden with Host of the target" - }, - "secComExcludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "URI patterns excluded from secured communications" - }, - "publicPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "By default, every services are private only and you'll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use '/.*'" - }, - "privatePatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "If you define a public pattern that is a little bit too much, you can make some of public URL private again" - }, - "ipFiltering" : { - "$ref" : "#/components/schemas/IpFiltering" - }, - "api" : { - "$ref" : "#/components/schemas/ExposedApi" - }, - "healthCheck" : { - "$ref" : "#/components/schemas/HealthCheck" - }, - "clientConfig" : { - "$ref" : "#/components/schemas/ClientConfig" - }, - "Canary" : { - "$ref" : "#/components/schemas/Canary" - }, - "statsdConfig" : { - "$ref" : "#/components/schemas/StatsdConfig" - }, - "chaosConfig" : { - "$ref" : "#/components/schemas/ChaosConfig" - }, - "jwtVerifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LocalJwtVerifier" - }, { - "$ref" : "#/components/schemas/RefJwtVerifier" - } ] - }, - "secComSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Just a bunch of random properties" - }, - "matchingHeaders" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that MUST be present on client request to route it. Useful to implement versioning" - }, - "additionalHeaders" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be added to each client request. Useful to add authentication" - }, - "authConfigRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to a global auth module config" - }, - "transformerRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to a request transformer" - }, - "clientValidatorRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to validation authority" - }, - "cors" : { - "$ref" : "#/components/schemas/CorsSettings" - }, - "redirection" : { - "$ref" : "#/components/schemas/RedirectionSettings" - }, - "gzip" : { - "$ref" : "#/components/schemas/Gzip" - }, - "headersVerification" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be verified after routing." - } - } - }, - "description" : "Current service descriptors at the time of export" - }, - "errorTemplates" : { - "type" : "array", - "items" : { - "description" : "Error templates for a service descriptor", - "type" : "object", - "required" : [ "serviceId", "template40x", "template50x", "templateBuild", "templateMaintenance", "messages" ], - "properties" : { - "serviceId" : { - "type" : "string", - "example" : "a string value", - "description" : "The Id of the service for which the error template is enabled" - }, - "template40x" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for 40x errors" - }, - "template50x" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for 50x errors" - }, - "templateBuild" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for build page" - }, - "templateMaintenance" : { - "type" : "string", - "example" : "a string value", - "description" : "The html template for maintenance page" - }, - "messages" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Map for custom messages" - } - } - }, - "description" : "Current error templates at the time of export" - } - } - }, - "ImportExportStats" : { - "description" : "Global stats for the current Otoroshi instances", - "type" : "object", - "required" : [ "calls", "dataIn", "dataOut" ], - "properties" : { - "calls" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Number of calls to Otoroshi globally" - }, - "dataIn" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The amount of data sent to Otoroshi globally" - }, - "dataOut" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The amount of data sent from Otoroshi globally" - } - } - }, - "IpFiltering" : { - "description" : "The filtering configuration block for a service of globally.", - "type" : "object", - "required" : [ "whitelist", "blacklist" ], - "properties" : { - "whitelist" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "ipv4", - "example" : "192.192.192.192" - }, - "description" : "Whitelisted IP addresses" - }, - "blacklist" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "ipv4", - "example" : "192.192.192.192" - }, - "description" : "Blacklisted IP addresses" - } - } - }, - "MailerSettings" : { - "description" : "Configuration for mailgun api client", - "type" : "object", - "required" : [ "apiKey", "domain" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "Type of the mailer: console, generic, mailgun, mailjet" - }, - "eu" : { - "type" : "boolean", - "example" : true, - "description" : "Mailgun mailer, use EU tenant api" - }, - "apiKey" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailgun mailer api key" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailgun mailer domain" - }, - "apiKeyPublic" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailjet mailer public api key" - }, - "apiKeyPrivate" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailjet mailer private api key" - }, - "url" : { - "type" : "string", - "example" : "a string value", - "description" : "Generic mailer url" - }, - "header" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Generic mailer headers" - } - } - }, - "Patch" : { - "description" : "A set of changes described in JSON Patch format: http://jsonpatch.com/ (RFC 6902)", - "type" : "array", - "items" : { - "type" : "object", - "required" : [ "op", "path" ], - "properties" : { - "op" : { - "type" : "string", - "enum" : [ "add", "replace", "remove", "copy", "test" ] - }, - "path" : { - "type" : "string", - "example" : "a string value" - }, - "value" : { } - } - } - }, - "Quotas" : { - "description" : "Quotas state for an api key on a service group", - "type" : "object", - "required" : [ "authorizedCallsPerSec", "currentCallsPerSec", "remainingCallsPerSec", "authorizedCallsPerDay", "currentCallsPerDay", "remainingCallsPerDay", "authorizedCallsPerMonth", "currentCallsPerMonth", "remainingCallsPerMonth" ], - "properties" : { - "authorizedCallsPerSec" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of authorized calls per second" - }, - "currentCallsPerSec" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The current number of calls per second" - }, - "remainingCallsPerSec" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The remaining number of calls per second" - }, - "authorizedCallsPerDay" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of authorized calls per day" - }, - "currentCallsPerDay" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The current number of calls per day" - }, - "remainingCallsPerDay" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The remaining number of calls per day" - }, - "authorizedCallsPerMonth" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of authorized calls per month" - }, - "currentCallsPerMonth" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The current number of calls per month" - }, - "remainingCallsPerMonth" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of authorized calls per month" - } - } - }, - "Service" : { - "description" : "An otoroshi service descriptor. Represent a forward HTTP call on a domain to another location with some optional api management mecanism", - "type" : "object", - "required" : [ "id", "groups", "name", "env", "domain", "subdomain", "targets", "root", "enabled", "privateApp", "forceHttps", "maintenanceMode", "buildMode", "enforceSecureCommunication" ], - "properties" : { - "id" : { - "type" : "string", - "format" : "uuid", - "example" : "110e8400-e29b-11d4-a716-446655440000", - "description" : "A unique random string to identify your service" - }, - "groups" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "example" : [ "a string value" ], - "description" : "Each service descriptor is attached to groups. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of your service. Only for debug and human readability purposes" - }, - "env" : { - "type" : "string", - "example" : "a string value", - "description" : "The line on which the service is available. Based on that value, the name of the line will be appended to the subdomain. For line prod, nothing will be appended. For example, if the subdomain is 'foo' and line is 'preprod', then the exposed service will be available at 'foo.preprod.mydomain'" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "The domain on which the service is available." - }, - "subdomain" : { - "type" : "string", - "example" : "a string value", - "description" : "The subdomain on which the service is available" - }, - "targets" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Target" - }, - "description" : "The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures" - }, - "root" : { - "type" : "string", - "example" : "a string value", - "description" : "Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar" - }, - "matchingRoot" : { - "type" : "string", - "example" : "a string value", - "description" : "The root path on which the service is available" - }, - "localHost" : { - "type" : "string", - "example" : "a string value", - "description" : "The host used localy, mainly localhost:xxxx" - }, - "localScheme" : { - "type" : "string", - "example" : "a string value", - "description" : "The scheme used localy, mainly http" - }, - "redirectToLocal" : { - "type" : "boolean", - "example" : true, - "description" : "If you work locally with Otoroshi, you may want to use that feature to redirect one particuliar service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist" - }, - "userFacing" : { - "type" : "boolean", - "example" : true, - "description" : "The fact that this service will be seen by users and cannot be impacted by the Snow Monkey" - }, - "privateApp" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, user will be allowed to use the service (UI) only if they are registered users of the private apps domain" - }, - "forceHttps" : { - "type" : "boolean", - "example" : true, - "description" : "Will force redirection to https:// if not present" - }, - "maintenanceMode" : { - "type" : "boolean", - "example" : true, - "description" : "Display a maintainance page when a user try to use the service" - }, - "buildMode" : { - "type" : "boolean", - "example" : true, - "description" : "Display a construction page when a user try to use the service" - }, - "enforceSecureCommunication" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, Otoroshi will try to exchange headers with downstream service to ensure no one else can use the service from outside" - }, - "sendOtoroshiHeadersBack" : { - "type" : "boolean", - "example" : true, - "description" : "When enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc ..." - }, - "xForwardedHeaders" : { - "type" : "boolean", - "example" : true, - "description" : "Send X-Forwarded-* headers" - }, - "overrideHost" : { - "type" : "boolean", - "example" : true, - "description" : "Host header will be overriden with Host of the target" - }, - "secComExcludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "URI patterns excluded from secured communications" - }, - "publicPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "By default, every services are private only and you'll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use '/.*'" - }, - "privatePatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "If you define a public pattern that is a little bit too much, you can make some of public URL private again" - }, - "ipFiltering" : { - "$ref" : "#/components/schemas/IpFiltering" - }, - "api" : { - "$ref" : "#/components/schemas/ExposedApi" - }, - "healthCheck" : { - "$ref" : "#/components/schemas/HealthCheck" - }, - "clientConfig" : { - "$ref" : "#/components/schemas/ClientConfig" - }, - "Canary" : { - "$ref" : "#/components/schemas/Canary" - }, - "statsdConfig" : { - "$ref" : "#/components/schemas/StatsdConfig" - }, - "chaosConfig" : { - "$ref" : "#/components/schemas/ChaosConfig" - }, - "jwtVerifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LocalJwtVerifier" - }, { - "$ref" : "#/components/schemas/RefJwtVerifier" - } ] - }, - "secComSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Just a bunch of random properties" - }, - "matchingHeaders" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that MUST be present on client request to route it. Useful to implement versioning" - }, - "additionalHeaders" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be added to each client request. Useful to add authentication" - }, - "authConfigRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to a global auth module config" - }, - "transformerRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to a request transformer" - }, - "clientValidatorRef" : { - "type" : "string", - "example" : "a string value", - "description" : "A reference to validation authority" - }, - "cors" : { - "$ref" : "#/components/schemas/CorsSettings" - }, - "redirection" : { - "$ref" : "#/components/schemas/RedirectionSettings" - }, - "gzip" : { - "$ref" : "#/components/schemas/Gzip" - }, - "headersVerification" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Specify headers that will be verified after routing." - } - } - }, - "SimpleAdmin" : { - "description" : "Administrator using just login/password tuple to access Otoroshi", - "type" : "object", - "required" : [ "username", "label", "password", "createdAt" ], - "properties" : { - "username" : { - "type" : "string", - "example" : "a string value", - "description" : "The email address of the user" - }, - "label" : { - "type" : "string", - "example" : "a string value", - "description" : "The label for the user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "The hashed password of the user" - }, - "createdAt" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The creation date of the user" - } - } - }, - "Stats" : { - "description" : "Live stats for a service or globally", - "type" : "object", - "required" : [ "calls", "dataIn", "dataOut", "rate", "duration", "overhead", "dataInRate", "dataOutRate", "concurrentHandledRequests" ], - "properties" : { - "calls" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Number of calls on the specified service or globally" - }, - "dataIn" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The amount of data sent to the specified service or Otoroshi globally" - }, - "dataOut" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The amount of data sent from the specified service or Otoroshi globally" - }, - "rate" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The rate of data sent from and to the specified service or Otoroshi globally" - }, - "duration" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The average duration for a call" - }, - "overhead" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The average overhead time induced by Otoroshi for each call" - }, - "dataInRate" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The rate of data sent to the specified service or Otoroshi globally" - }, - "dataOutRate" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The rate of data sent from the specified service or Otoroshi globally" - }, - "concurrentHandledRequests" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The number of concurrent request currently" - } - } - }, - "StatsdConfig" : { - "description" : "The configuration for statsd metrics push", - "type" : "object", - "required" : [ "host", "port", "datadog" ], - "properties" : { - "host" : { - "type" : "string", - "example" : "a string value", - "description" : "The host of the StatsD agent" - }, - "port" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The port of the StatsD agent" - }, - "datadog" : { - "type" : "boolean", - "example" : true, - "description" : "Datadog agent" - } - } - }, - "Target" : { - "description" : "A Target is where an HTTP call will be forwarded in the end from a service domain", - "type" : "object", - "required" : [ "host", "scheme" ], - "properties" : { - "host" : { - "type" : "string", - "format" : "hostname", - "example" : "www.google.com", - "description" : "The host on which the HTTP call will be forwarded. Can be a domain name, or an IP address. Can also have a port" - }, - "scheme" : { - "type" : "string", - "example" : "a string value", - "description" : "The protocol used for communication. Can be http or https" - } - } - }, - "U2FAdmin" : { - "description" : "Administrator using FIDO U2F device to access Otoroshi", - "type" : "object", - "required" : [ "username", "label", "password", "createdAt", "registration" ], - "properties" : { - "username" : { - "type" : "string", - "example" : "a string value", - "description" : "The email address of the user" - }, - "label" : { - "type" : "string", - "example" : "a string value", - "description" : "The label for the user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "The hashed password of the user" - }, - "createdAt" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The creation date of the user" - }, - "registration" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The U2F registration slug" - } - } - }, - "Webhook" : { - "description" : "A callback URL where events are posted", - "type" : "object", - "required" : [ "url", "headers" ], - "properties" : { - "url" : { - "type" : "string", - "format" : "uri", - "example" : "http://www.google.com", - "description" : "The URL where events are posted" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Headers to authorize the call or whatever" - } - } - }, - "BadResponse" : { - "description" : "An HTTP response that is not supposed to be returned by a service", - "type" : "object", - "required" : [ "status", "body", "headers" ], - "properties" : { - "status" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The HTTP status for the response" - }, - "body" : { - "type" : "string", - "example" : "a string value", - "description" : "The body of the HTTP response" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The HTTP headers of the response" - } - } - }, - "LargeRequestFaultConfig" : { - "description" : "Config for large request injection fault", - "type" : "object", - "required" : [ "ratio", "additionalRequestSize" ], - "properties" : { - "ratio" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0" - }, - "additionalRequestSize" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The size added to the request body in bytes. Added payload will be spaces only." - } - } - }, - "LargeResponseFaultConfig" : { - "description" : "Config for large response injection fault", - "type" : "object", - "required" : [ "ratio", "additionalResponseSize" ], - "properties" : { - "ratio" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0" - }, - "additionalRequestSize" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The size added to the response body in bytes. Added payload will be spaces only." - } - } - }, - "LatencyInjectionFaultConfig" : { - "description" : "Config for large latency injection fault", - "type" : "object", - "required" : [ "ratio", "from", "to" ], - "properties" : { - "ratio" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0" - }, - "from" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The start range of latency added to the request" - }, - "to" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The end range of latency added to the request" - } - } - }, - "BadResponsesFaultConfig" : { - "description" : "Config for bad requests injection fault", - "type" : "object", - "required" : [ "ratio", "responses" ], - "properties" : { - "ratio" : { - "type" : "integer", - "format" : "double", - "example" : 42.2, - "description" : "The percentage of requests affected by this fault. Value should be between 0.0 and 1.0" - }, - "responses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/BadResponse" - }, - "description" : "The possibles responses" - } - } - }, - "ChaosConfig" : { - "description" : "Configuration for the faults that can be injected in requests", - "type" : "object", - "required" : [ "enabled" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not this config is enabled" - }, - "largeRequestFaultConfig" : { - "$ref" : "#/components/schemas/LargeRequestFaultConfig" - }, - "largeResponseFaultConfig" : { - "$ref" : "#/components/schemas/LargeResponseFaultConfig" - }, - "latencyInjectionFaultConfig" : { - "$ref" : "#/components/schemas/LatencyInjectionFaultConfig" - }, - "badResponsesFaultConfig" : { - "$ref" : "#/components/schemas/BadResponsesFaultConfig" - } - } - }, - "OutageStrategy" : { - "type" : "string", - "enum" : [ "OneServicePerGroup", "AllServicesPerGroup" ] - }, - "SnowMonkeyConfig" : { - "description" : "Configuration for the faults that can be injected in requests. The name Snow Monkey is an hommage to Netflix's Chaos Monkey 😉", - "type" : "object", - "required" : [ "enabled", "outageStrategy", "includeUserFacingDescriptors", "dryRun", "timesPerDay", "startTime", "stopTime", "outageDurationFrom", "outageDurationTo", "targetGroups", "chaosConfig" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not this config is enabled" - }, - "outageStrategy" : { - "$ref" : "#/components/schemas/OutageStrategy", - "description" : "" - }, - "includeUserFacingDescriptors" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not user facing apps. will be impacted by Snow Monkey" - }, - "dryRun" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not outages will actualy impact requests" - }, - "timesPerDay" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Number of time per day each service will be outage" - }, - "startTime" : { - "type" : "string", - "format" : "time", - "example" : "17:32:28.000", - "description" : "Start time of Snow Monkey each day" - }, - "stopTime" : { - "type" : "string", - "format" : "time", - "example" : "17:32:28.000", - "description" : "Stop time of Snow Monkey each day" - }, - "outageDurationFrom" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Start of outage duration range" - }, - "outageDurationTo" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "End of outage duration range" - }, - "targetGroups" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Groups impacted by Snow Monkey. If empty, all groups will be impacted" - }, - "chaosConfig" : { - "$ref" : "#/components/schemas/ChaosConfig" - } - } - }, - "Outage" : { - "description" : "An outage by the Snow Monkey on a service", - "type" : "object", - "required" : [ "descriptorId", "descriptorName", "until", "duration" ], - "properties" : { - "descriptorId" : { - "type" : "string", - "example" : "a string value", - "description" : "The service impacted by outage" - }, - "descriptorName" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of service impacted by outage" - }, - "until" : { - "type" : "string", - "format" : "time", - "example" : "17:32:28.000", - "description" : "The end of the outage" - }, - "duration" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The duration of the outage" - } - } - }, - "RefJwtVerifier" : { - "description" : "Reference to a global JWT verifier", - "type" : "object", - "required" : [ "type", "id", "enabled" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "A string with value 'ref'" - }, - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "The id of the GlobalJWTVerifier" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Is it enabled" - } - } - }, - "LocalJwtVerifier" : { - "description" : "A JWT verifier used only for the current service descriptor", - "type" : "object", - "required" : [ "type", "enabled", "strict", "source", "algoSettings", "strategy" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "A string with value 'local'" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Is it enabled" - }, - "strict" : { - "type" : "boolean", - "example" : true, - "description" : "Does it fail if JWT not found" - }, - "source" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/InQueryParam" - }, { - "$ref" : "#/components/schemas/InHeader" - }, { - "$ref" : "#/components/schemas/InCookie" - } ] - }, - "algoSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - }, - "strategy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/PassThrough" - }, { - "$ref" : "#/components/schemas/Sign" - }, { - "$ref" : "#/components/schemas/Transform" - } ] - } - } - }, - "InQueryParam" : { - "description" : "JWT location in a query param", - "type" : "object", - "required" : [ "type", "name" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value InQueryParam" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the query param" - } - } - }, - "InHeader" : { - "description" : "JWT location in a header", - "type" : "object", - "required" : [ "type", "name", "remove" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value InHeader" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the header" - }, - "remove" : { - "type" : "string", - "example" : "a string value", - "description" : "Remove regex inside the value, like 'Bearer '" - } - } - }, - "InCookie" : { - "description" : "JWT location in a cookie", - "type" : "object", - "required" : [ "type", "name" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value InCookie" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the cookie" - } - } - }, - "HSAlgoSettings" : { - "description" : "Settings for an HMAC + SHA signing algorithm", - "type" : "object", - "required" : [ "type", "size", "secret" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value HSAlgoSettings" - }, - "size" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Size for SHA function. can be 256, 384 or 512" - }, - "secret" : { - "type" : "string", - "example" : "a string value", - "description" : "The secret value for the HMAC function" - } - } - }, - "RSAlgoSettings" : { - "description" : "Settings for an HMAC + SHA signing algorithm", - "type" : "object", - "required" : [ "type", "size", "publicKey" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value RSAlgoSettings" - }, - "size" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Size for SHA function. can be 256, 384 or 512" - }, - "publicKey" : { - "type" : "string", - "example" : "a string value", - "description" : "The public key for the RSA function" - }, - "privateKey" : { - "type" : "string", - "example" : "a string value", - "description" : "The private key for the RSA function" - } - } - }, - "ESAlgoSettings" : { - "description" : "Settings for an EC + SHA signing algorithm", - "type" : "object", - "required" : [ "type", "size", "publicKey" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value ESAlgoSettings" - }, - "size" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Size for SHA function. can be 256, 384 or 512" - }, - "publicKey" : { - "type" : "string", - "example" : "a string value", - "description" : "The public key for the RSA function" - }, - "privateKey" : { - "type" : "string", - "example" : "a string value", - "description" : "The private key for the RSA function" - } - } - }, - "JWKSAlgoSettings" : { - "description" : "Settings for a JWK set", - "type" : "object", - "required" : [ "type", "size", "publicKey" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value JWKSAlgoSettings" - }, - "url" : { - "type" : "string", - "example" : "a string value", - "description" : "The url for the http call" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The headers for the http call" - }, - "timeout" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The timeout of the http call" - }, - "ttl" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The ttl of the keyset" - }, - "kty" : { - "type" : "string", - "example" : "a string value", - "description" : "The type of key: RSA or EC" - } - } - }, - "MappingSettings" : { - "description" : "Settings to change fields of a JWT token", - "type" : "object", - "required" : [ "map", "values", "remove" ], - "properties" : { - "map" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Fields to rename" - }, - "values" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Fields to set" - }, - "remove" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Fields to remove" - } - } - }, - "TransformSettings" : { - "description" : "Settings to transform a JWT token and its location", - "type" : "object", - "required" : [ "location", "mappingSettings" ], - "properties" : { - "location" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/InQueryParam" - }, { - "$ref" : "#/components/schemas/InHeader" - }, { - "$ref" : "#/components/schemas/InCookie" - } ] - }, - "mappingSettings" : { - "$ref" : "#/components/schemas/MappingSettings" - } - } - }, - "VerificationSettings" : { - "description" : "Settings to verify the value of JWT token fields", - "type" : "object", - "required" : [ "fields" ], - "properties" : { - "fields" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Fields to verify with their values" - }, - "mappingSettings" : { - "$ref" : "#/components/schemas/MappingSettings" - } - } - }, - "PassThrough" : { - "description" : "Strategy where only signature and field values are verified", - "type" : "object", - "required" : [ "type", "verificationSettings" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value PassThrough" - }, - "verificationSettings" : { - "$ref" : "#/components/schemas/VerificationSettings" - } - } - }, - "Sign" : { - "description" : "Strategy where signature and field values are verified, and then token si re-signed", - "type" : "object", - "required" : [ "type", "verificationSettings", "algoSettings" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value Sign" - }, - "verificationSettings" : { - "$ref" : "#/components/schemas/VerificationSettings" - }, - "algoSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - } - } - }, - "Transform" : { - "description" : "Strategy where signature and field values are verified, trasnformed and then token si re-signed", - "type" : "object", - "required" : [ "type", "verificationSettings", "algoSettings" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "String with value Transform" - }, - "verificationSettings" : { - "$ref" : "#/components/schemas/VerificationSettings" - }, - "transformSettings" : { - "$ref" : "#/components/schemas/TransformSettings" - }, - "algoSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - } - } - }, - "GlobalJwtVerifier" : { - "description" : "A JWT verifier used by multiple service descriptor", - "type" : "object", - "required" : [ "type", "id", "name", "desc", "enabled", "strict", "source", "algoSettings", "strategy" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Verifier id" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Verifier name" - }, - "desc" : { - "type" : "string", - "example" : "a string value", - "description" : "Verifier description" - }, - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Is it enabled" - }, - "strict" : { - "type" : "boolean", - "example" : true, - "description" : "Does it fail if JWT not found" - }, - "source" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/InQueryParam" - }, { - "$ref" : "#/components/schemas/InHeader" - }, { - "$ref" : "#/components/schemas/InCookie" - } ] - }, - "algoSettings" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ] - }, - "strategy" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/PassThrough" - }, { - "$ref" : "#/components/schemas/Sign" - }, { - "$ref" : "#/components/schemas/Transform" - } ] - } - } - }, - "GenericOauth2ModuleConfig" : { - "description" : "Settings to authenticate users using a generic OAuth2 provider", - "type" : "object", - "required" : [ "type", "id", "name", "desc", "sessionMaxAge", "clientId", "clientSecret", "authorizeUrl", "tokenUrl", "userInfoUrl", "loginUrl", "logoutUrl", "callbackUrl", "accessTokenField", "nameField", "emailField", "otoroshiDataField" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "Type of settings. value is oauth2" - }, - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Unique id of the config" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the config" - }, - "desc" : { - "type" : "string", - "example" : "a string value", - "description" : "Description of the config" - }, - "sessionMaxAge" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Max age of the session" - }, - "clientId" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth Client id" - }, - "clientSecret" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth Client secret" - }, - "authorizeUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth authorize URL" - }, - "tokenUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth token URL" - }, - "userInfoUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth userinfo to get user profile" - }, - "loginUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth login URL" - }, - "logoutUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "OAuth logout URL" - }, - "callbackUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "Otoroshi callback URL" - }, - "scope" : { - "type" : "string", - "example" : "a string value", - "description" : "The scope of the token" - }, - "claims" : { - "type" : "string", - "example" : "a string value", - "description" : "The claims of the token" - }, - "accessTokenField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get access token" - }, - "nameField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get name from user profile" - }, - "emailField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get email from user profile" - }, - "otoroshiDataField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get otoroshi metadata from. You can specify sub fields using | as separator" - }, - "oidConfig" : { - "type" : "string", - "example" : "a string value", - "description" : "URL of the OIDC config. file" - }, - "useJson" : { - "type" : "boolean", - "example" : true, - "description" : "Use JSON or URL Form Encoded as payload with the OAuth provider" - }, - "useCookies" : { - "type" : "boolean", - "example" : true, - "description" : "Use for redirection to actual service" - }, - "readProfileFromToken" : { - "type" : "boolean", - "example" : true, - "description" : "The user profile will be read from the JWT token in id_token" - }, - "jwtVerifier" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/HSAlgoSettings" - }, { - "$ref" : "#/components/schemas/RSAlgoSettings" - }, { - "$ref" : "#/components/schemas/ESAlgoSettings" - }, { - "$ref" : "#/components/schemas/JWKSAlgoSettings" - } ], - "description" : "Algo. settings to verify JWT token" - } - } - }, - "InMemoryAuthModuleConfig" : { - "description" : "Settings to authenticate users using the in memory user store", - "type" : "object", - "required" : [ "type", "id", "name", "desc", "users", "sessionMaxAge" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "Type of settings. value is basic" - }, - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Unique id of the config" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the config" - }, - "desc" : { - "type" : "string", - "example" : "a string value", - "description" : "Description of the config" - }, - "sessionMaxAge" : { - "type" : "string", - "example" : "a string value", - "description" : "Max age of the session" - }, - "users" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/InMemoryUser" - }, - "description" : "List of users" - } - } - }, - "LdapAuthModuleConfig" : { - "description" : "Settings to authenticate users using a generic OAuth2 provider", - "type" : "object", - "required" : [ "type", "id", "name", "desc", "sessionMaxAge", "serverUrl", "searchBase", "userBase", "groupFilter", "searchFilter", "adminUsername", "adminPassword", "nameField", "emailField", "metadataField" ], - "properties" : { - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "Type of settings. value is ldap" - }, - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Unique id of the config" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the config" - }, - "desc" : { - "type" : "string", - "example" : "a string value", - "description" : "Description of the config" - }, - "sessionMaxAge" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Max age of the session" - }, - "serverUrl" : { - "type" : "string", - "example" : "a string value", - "description" : "URL of the ldap server" - }, - "searchBase" : { - "type" : "string", - "example" : "a string value", - "description" : "LDAP search base" - }, - "userBase" : { - "type" : "string", - "example" : "a string value", - "description" : "LDAP user base DN" - }, - "groupFilter" : { - "type" : "string", - "example" : "a string value", - "description" : "Filter for groups" - }, - "searchFilter" : { - "type" : "string", - "example" : "a string value", - "description" : "Filter for users" - }, - "adminUsername" : { - "type" : "string", - "example" : "a string value", - "description" : "The admin username" - }, - "adminPassword" : { - "type" : "string", - "example" : "a string value", - "description" : "The admin password" - }, - "nameField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get name from user profile" - }, - "emailField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get email from user profile" - }, - "otoroshiDataField" : { - "type" : "string", - "example" : "a string value", - "description" : "Field name to get otoroshi metadata from. You can specify sub fields using | as separator" - } - } - }, - "CorsSettings" : { - "description" : "The configuration for cors support", - "type" : "object", - "required" : [ "enabled", "allowOrigin", "exposeHeaders", "allowHeaders", "allowMethods", "excludedPatterns", "maxAge", "allowCredentials" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not cors is enabled" - }, - "allowOrigin" : { - "type" : "string", - "example" : "a string value", - "description" : "The cors allowed origin" - }, - "exposeHeaders" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "The cors exposed header" - }, - "allowHeaders" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "The cors allowed headers" - }, - "allowMethods" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "The cors allowed methods" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "The cors excluded patterns" - }, - "maxAge" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Cors max age" - }, - "allowCredentials" : { - "type" : "boolean", - "example" : true, - "description" : "Allow to pass credentials" - } - } - }, - "RedirectionSettings" : { - "description" : "The configuration for redirection per service", - "type" : "object", - "required" : [ "enabled", "to", "code" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether or not redirection is enabled" - }, - "to" : { - "type" : "string", - "example" : "a string value", - "description" : "The location for redirection" - }, - "code" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "The http redirect code" - } - } - }, - "InMemoryUser" : { - "description" : "A user", - "type" : "object", - "required" : [ "name", "password", "email", "metadata" ], - "properties" : { - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the user" - }, - "email" : { - "type" : "string", - "example" : "a string value", - "description" : "Email of the user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "Password of the user (BCrypt hash)" - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata of the user" - } - } - }, - "LdapUser" : { - "description" : "A user", - "type" : "object", - "required" : [ "name", "email", "metadata" ], - "properties" : { - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name of the user" - }, - "email" : { - "type" : "string", - "example" : "a string value", - "description" : "Email of the user" - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata of the user" - } - } - }, - "Gzip" : { - "description" : "Configuration for gzip of service responses", - "type" : "object", - "required" : [ "enabled", "excludedPatterns", "whiteList", "blackList", "bufferSize", "chunkedThreshold", "compressionLevel" ], - "properties" : { - "enabled" : { - "type" : "boolean", - "example" : true, - "description" : "Whether gzip compression is enabled or not" - }, - "excludedPatterns" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Patterns that are excluded from gzipping" - }, - "whiteList" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Whitelisted mime types. Wildcard supported" - }, - "blackList" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Blacklisted mime types. Wildcard supported" - }, - "bufferSize" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Size of the GZip buffer" - }, - "chunkedThreshold" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "Threshold for chunking data" - }, - "compressionLevel" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Compression level. From 0 to 9" - } - } - }, - "Script" : { - "description" : "A script to transformer otoroshi requests ", - "type" : "object", - "required" : [ "id", "name", "desc", "code" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "The id of the script" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the script" - }, - "desc" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The description of the script" - }, - "code" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The code of the script" - } - } - }, - "ScriptCompilationResult" : { - "description" : "The result of the compilation of a Script", - "type" : "object", - "required" : [ "done" ], - "properties" : { - "done" : { - "type" : "boolean", - "example" : true, - "description" : "Is the task done or not" - }, - "error" : { - "$ref" : "#/components/schemas/ScriptCompilationError" - } - } - }, - "ScriptCompilationError" : { - "description" : "The error of the compilation of a Script", - "type" : "object", - "required" : [ "line", "column", "file", "rawMessage", "message" ], - "properties" : { - "line" : { - "type" : "string", - "example" : "a string value", - "description" : "The line of the error" - }, - "column" : { - "type" : "string", - "example" : "a string value", - "description" : "The column of the error" - }, - "file" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The file where the error is located" - }, - "rawMessage" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The raw message from the compiler" - }, - "message" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "The message to display for the error" - } - } - }, - "Certificate" : { - "description" : "A SSL/TLS X509 certificate", - "type" : "object", - "required" : [ "id", "chain", "privateKey", "caRef", "domain", "selfSigned", "ca", "valid", "autoRenew", "subject", "from", "to" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Id of the certificate" - }, - "chain" : { - "type" : "string", - "example" : "a string value", - "description" : "Certificate chain of trust in PEM format" - }, - "privateKey" : { - "type" : "string", - "example" : "a string value", - "description" : "PKCS8 private key in PEM format" - }, - "caRef" : { - "type" : "string", - "example" : "a string value", - "description" : "Reference for a CA certificate in otoroshi" - }, - "autoRenew" : { - "type" : "string", - "example" : "a string value", - "description" : "Allow Otoroshi to renew the certificate (if self signed)" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "Domain of the certificate (read only)" - }, - "selfSigned" : { - "type" : "string", - "example" : "a string value", - "description" : "Certificate is self signed read only)" - }, - "ca" : { - "type" : "string", - "example" : "a string value", - "description" : "Certificate is a CA (read only)" - }, - "valid" : { - "type" : "string", - "example" : "a string value", - "description" : "Certificate is valid (read only)" - }, - "subject" : { - "type" : "string", - "example" : "a string value", - "description" : "Subject of the certificate (read only)" - }, - "from" : { - "type" : "string", - "example" : "a string value", - "description" : "Start date of validity" - }, - "to" : { - "type" : "string", - "example" : "a string value", - "description" : "End date of validity" - } - } - }, - "ValidationAuthority" : { - "description" : "Settings to access a validation authority server", - "type" : "object", - "required" : [ "id", "name", "description", "url", "host", "goodTtl", "badTtl", "method", "path", "timeout", "noCache", "alwaysValid", "headers" ], - "properties" : { - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "The id of the settings" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "The name of the settings" - }, - "description" : { - "type" : "string", - "example" : "a string value", - "description" : "The description of the settings" - }, - "url" : { - "type" : "string", - "example" : "a string value", - "description" : "The URL of the server" - }, - "host" : { - "type" : "string", - "example" : "a string value", - "description" : "The host of the server" - }, - "goodTtl" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The TTL for valid access response caching" - }, - "badTtl" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The TTL for invalid access response caching" - }, - "method" : { - "type" : "string", - "example" : "a string value", - "description" : "The HTTP method" - }, - "path" : { - "type" : "string", - "example" : "a string value", - "description" : "The URL path" - }, - "timeout" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "The call timeout" - }, - "noCache" : { - "type" : "boolean", - "example" : true, - "description" : "Avoid caching responses" - }, - "alwaysValid" : { - "type" : "boolean", - "example" : true, - "description" : "Bypass http calls, every certificates are valids" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "HTTP call headers" - } - } - }, - "KafkaConfig" : { - "description" : "The configuration for kafka access", - "type" : "object", - "required" : [ "servers" ], - "properties" : { - "servers" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "URLs of the kafka servers" - }, - "keyPass" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional keypass" - }, - "keyStore" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional path to keystore" - }, - "trustore" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional path to trustore" - }, - "topic" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional kafka topic (otoroshi-events by default)" - } - } - }, - "ElasticConfig" : { - "description" : "The configuration for elastic access", - "type" : "object", - "required" : [ "clusterUri", "index", "type", "user", "password", "headers" ], - "properties" : { - "clusterUri" : { - "type" : "string", - "example" : "a string value", - "description" : "URL of the elastic cluster" - }, - "index" : { - "type" : "string", - "example" : "a string value", - "description" : "Index for events. Default is otoroshi-events" - }, - "type" : { - "type" : "string", - "example" : "a string value", - "description" : "Type of events. Default is event" - }, - "user" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional user" - }, - "password" : { - "type" : "string", - "example" : "a string value", - "description" : "Optional password" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Additionnal http headers" - } - } - }, - "whebhookConfig" : { - "description" : "The configuration for webhook", - "type" : "object", - "required" : [ "servers" ], - "properties" : { - "url" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "URLs of the webhook" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Optional headers" - } - } - }, - "PulsarDataExporterConfig" : { - "description" : "The configuration for kafka access", - "type" : "object", - "required" : [ "uri", "tenant", "namespace", "topic" ], - "properties" : { - "uri" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "URI of the pulsar server" - }, - "tenant" : { - "type" : "string", - "example" : "a string value", - "description" : "Tenant" - }, - "namespace" : { - "type" : "string", - "example" : "a string value", - "description" : "Namespace" - }, - "topic" : { - "type" : "string", - "example" : "a string value", - "description" : "Topic" - } - } - }, - "FileDataExporterConfig" : { - "type" : "object", - "required" : [ "path" ], - "properties" : { - "path" : { - "type" : "string", - "example" : "a string value", - "description" : "Path to file" - } - } - }, - "MailerGenericExporterConfig" : { - "type" : "object", - "required" : [ "type" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "generic" ], - "description" : "Type of mailer" - }, - "url" : { - "type" : "string", - "example" : "a string value", - "description" : "Url of mailer" - }, - "headers" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Optional headers" - }, - "to" : { - "type" : "array", - "items" : { - "type" : "string", - "example" : "a string value" - }, - "description" : "Email adresses of recipents" - } - } - }, - "MailerConsoleExporterConfig" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "generic" ], - "description" : "Type of mailer" - } - } - }, - "MailerMailgunExporterConfig" : { - "type" : "object", - "required" : [ "type" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "mailgun" ], - "description" : "Type of mailer" - }, - "eu" : { - "type" : "boolean", - "example" : true, - "description" : "Whether the mailgun server is european" - }, - "apiKey" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailgun apiKey" - }, - "domain" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailgun domain" - }, - "to" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "email", - "example" : "admin@otoroshi.io" - }, - "description" : "Email adresses of recipents" - } - } - }, - "MailerMailjetExporterConfig" : { - "type" : "object", - "required" : [ "type" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "mailjet" ], - "description" : "Type of mailer" - }, - "apiKeyPublic" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailjet public apiKey" - }, - "apiKeyPrivate" : { - "type" : "string", - "example" : "a string value", - "description" : "Mailjet private apiKey" - }, - "to" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "email", - "example" : "admin@otoroshi.io" - }, - "description" : "Email adresses of recipents" - } - } - }, - "MailerSendgridExporterConfig" : { - "type" : "object", - "required" : [ "type" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "sendgrid" ], - "description" : "Type of mailer" - }, - "apiKeyPublic" : { - "type" : "string", - "example" : "a string value", - "description" : "Sendgrid apiKey" - }, - "to" : { - "type" : "array", - "items" : { - "type" : "string", - "format" : "email", - "example" : "admin@otoroshi.io" - }, - "description" : "Email adresses of recipents" - } - } - }, - "ConsoleDataExporterConfig" : { - "type" : "object", - "properties" : { } - }, - "CustomDataExporterConfig" : { - "type" : "object", - "required" : [ "ref", "config" ], - "properties" : { - "ref" : { - "type" : "string", - "example" : "a string value", - "description" : "Script Ref" - }, - "config" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Custom data exporter config" - } - } - }, - "DataExporterConfig" : { - "description" : "Settings to export Otorshi events", - "type" : "object", - "properties" : { - "enabled" : { - "type" : "string", - "example" : "a string value", - "description" : "Boolean" - }, - "typ" : { - "type" : "string", - "enum" : [ "kafka", "pulsar", "file", "mailer", "elastic", "console", "custom" ], - "description" : "Type of data exporter" - }, - "id" : { - "type" : "string", - "example" : "a string value", - "description" : "Id" - }, - "name" : { - "type" : "string", - "example" : "a string value", - "description" : "Name" - }, - "desc" : { - "type" : "string", - "example" : "a string value", - "description" : "Description" - }, - "metadata" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "Metadata" - }, - "location" : { - "$ref" : "#/components/schemas/Location", - "description" : "location" - }, - "bufferSize" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "buffer size" - }, - "jsonWorkers" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "nb workers" - }, - "sendWorkers" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "send workers" - }, - "groupSize" : { - "type" : "integer", - "format" : "int32", - "example" : 123123, - "description" : "Group size" - }, - "groupDuration" : { - "type" : "integer", - "format" : "int64", - "example" : 123, - "description" : "duration" - }, - "filtering" : { - "$ref" : "#/components/schemas/Filtering", - "description" : "filtering" - }, - "projection" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - }, - "description" : "projection" - }, - "config" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/ElasticConfig" - }, { - "$ref" : "#/components/schemas/KafkaConfig" - }, { - "$ref" : "#/components/schemas/PulsarDataExporterConfig" - }, { - "$ref" : "#/components/schemas/FileDataExporterConfig" - }, { - "$ref" : "#/components/schemas/MailerGenericExporterConfig" - }, { - "$ref" : "#/components/schemas/MailerConsoleExporterConfig" - }, { - "$ref" : "#/components/schemas/MailerMailgunExporterConfig" - }, { - "$ref" : "#/components/schemas/MailerMailjetExporterConfig" - }, { - "$ref" : "#/components/schemas/MailerSendgridExporterConfig" - }, { - "$ref" : "#/components/schemas/ConsoleDataExporterConfig" - }, { - "$ref" : "#/components/schemas/CustomDataExporterConfig" - } ], - "description" : "Data Exporter config" - } - } - }, - "Location" : { - "type" : "object", - "required" : [ "tenant", "teams" ], - "properties" : { - "tenant" : { - "type" : "string", - "example" : "a string value", - "description" : "Tenant id" - }, - "teams" : { - "type" : "array", - "items" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - } - }, - "description" : "Team ids" - } - } - }, - "Filtering" : { - "type" : "object", - "required" : [ "include, exclude" ], - "properties" : { - "include" : { - "type" : "array", - "items" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - } - }, - "description" : "Including pattern" - }, - "exclude" : { - "type" : "array", - "items" : { - "type" : "object", - "example" : { - "key" : "value" - }, - "additionalProperties" : { - "type" : "string" - } - }, - "description" : "Excluding pattern" - } - } - } - } - } -} \ No newline at end of file diff --git a/docs/manual/content-pretty.json b/docs/manual/content-pretty.json deleted file mode 100644 index 6b76f7dd8f..0000000000 --- a/docs/manual/content-pretty.json +++ /dev/null @@ -1,492 +0,0 @@ -[ - { - "name": "about.md", - "id": "/about.md", - "url": "/about.html", - "title": "About Otoroshi", - "content": "# About Otoroshi\n\nAt the beginning of 2017, we had the need to create a new environment to be able to create new \"digital\" products very quickly in an agile fashion at @link:[MAIF](https://www.maif.fr) { open=new }. Naturally we turned to PaaS solutions and chose the excellent @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } product to run our apps. \n\nWe also chose that every feature team will have the freedom to choose its own technological stack to build its product. It was a nice move but it has also introduced some challenges in terms of homogeneity for traceability, security, logging, ... because we did not want to force library usage in the products. We could have used something like @link:[Service Mesh Pattern](http://philcalcado.com/2017/08/03/pattern_service_mesh.html) { open=new } but the deployement model of @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } prevented us to do it.\n\nThe right solution was to use a reverse proxy or some kind of API Gateway able to provide tracability, logging, security with apikeys, quotas, DNS as a service locator, etc. We needed something easy to use, with a human friendly UI, a nice API to extends its features, true hot reconfiguration, able to generate internal events for third party usage. A couple of solutions were available at that time, but not one seems to fit our needs, there was always something missing, too complicated for our needs or not playing well with @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } deployment model.\n\nAt some point, we tried to write a small prototype to explore what could be our dream reverse proxy. The design was very simple, there were some rough edges but every major feature needed was there waiting to be enhanced.\n\n**Otoroshi** was born and we decided to move ahead with our hairy monster :)\n\n## Philosophy \n\nEvery OSS product build at @link:[MAIF](https://www.maif.fr) { open=new } like the develoer portal @link:[Daikoku](https://maif.github.io/daikoku) { open=new } or @link:[Izanami](https://maif.github.io/izanami) { open=new } follow a common philosophy. \n\n* the services or API provided should be **technology agnostic**.\n* **http first**: http is the right answer to the previous quote \n* **api First**: the UI is just another client of the api. \n* **secured**: the services exposed need authentication for both humans or machines \n* **event based**: the services should expose a way to get notified of what happened inside. \n" - }, - { - "name": "api.md", - "id": "/api.md", - "url": "/api.html", - "title": "Admin REST API", - "content": "# Admin REST API\n\nOtoroshi provides a fully featured REST admin API to perform almost every operation possible in the Otoroshi dashboard. The Otoroshi dashbaord is just a regular consumer of the admin API.\n\nUsing the admin API, you can do whatever you want and enhance your Otoroshi instances with a lot of features that will feet your needs.\n\n## Swagger descriptor\n\nThe Otoroshi admin API is described using OpenAPI format and is available at :\n\nhttps://maif.github.io/otoroshi/manual/code/openapi.json\n\nEvery Otoroshi instance provides its own embedded OpenAPI descriptor at :\n\nhttp://otoroshi.oto.tools:8080/api/openapi.json\n\n## Swagger documentation\n\nYou can read the OpenAPI descriptor in a more human friendly fashion using `Swagger UI`. The swagger UI documentation of the Otoroshi admin API is available at :\n\nhttps://maif.github.io/otoroshi/swagger-ui/index.html\n\nEvery Otoroshi instance provides its own embedded OpenAPI descriptor at :\n\nhttp://otoroshi.oto.tools:8080/api/swagger/ui\n\nYou can also read the swagger UI documentation of the Otoroshi admin API below :\n\n@@@ div { .swagger-frame }\n\n\n@@@\n" - }, - { - "name": "architecture.md", - "id": "/architecture.md", - "url": "/architecture.html", - "title": "Architecture", - "content": "# Architecture\n\nWhen we started the development of Otoroshi, we had several classical patterns in mind like `Service gateway`, `Service locator`, `Circuit breakers`, etc ...\n\nAt start we thought about providing a bunch of librairies that would be included in each microservice or app to perform these tasks. But the more we were thinking about it, the more it was feeling weird, unagile, etc, it also prevented us to use any technical stack we wanted to use. So we decided to change our approach to something more universal.\n\nWe chose to make Otoroshi the central part of our microservices system, something between a reverse-proxy, a service gateway and a service locator where each call to a microservice (even from another microservice) must pass through Otoroshi. There are multiple benefits to do that, each call can be logged, audited, monitored, integrated with a circuit breaker, etc without imposing libraries and technical stack. Any service is exposed through its own domain and we rely only on DNS to handle the service location part. Any access to a service is secured by default with an api key and is supervised by a circuit breaker to avoid cascading failures.\n\n@@@ div { .centered-img }\n\n@@@\n\nOtoroshi tries to embrace our @ref:[global philosophy](./about.md#philosophy) by providing a full featured REST admin api, a gorgeous admin dashboard written in @link:[React](https://reactjs.org) { open=new } that uses the api, by generating traffic events, alerts events, audit events that can be consumed by several channels. Otoroshi also supports a bunch of datastores to better match with different use cases.\n\n@@@ div { .centered-img }\n\n@@@\n" - }, - { - "name": "aws.md", - "id": "/deploy/aws.md", - "url": "/deploy/aws.html", - "title": "AWS - Elastic Beanstalk", - "content": "# AWS - Elastic Beanstalk\n\nNow you want to use Otoroshi on AWS. There are multiple options to deploy Otoroshi on AWS, \nfor instance :\n\n* You can deploy the @ref:[Docker image](../install/get-otoroshi.md#from-docker) on [Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n* You can create a basic [Amazon EC2](https://docs.aws.amazon.com/fr_fr/AWSEC2/latest/UserGuide/concepts.html), access it via SSH, then \ndeploy the @ref:[otoroshi.jar](../install/get-otoroshi.md#from-jar-file) \n* Or you can use [AWS Elastic Beanstalk](https://aws.amazon.com/fr/elasticbeanstalk)\n\nIn this section we are going to cover how to deploy Otoroshi on [AWS Elastic Beanstalk](https://aws.amazon.com/fr/elasticbeanstalk). \n\n## AWS Elastic Beanstalk Overview\nUnlike Clever Cloud, to deploy an application on AWS Elastic Beanstalk, you don't link your app to your VCS repository, push your code and expect it to be built and run.\n\nAWS Elastic Beanstalk does only the run part. So you have to handle your own build pipeline, upload a Zip file containing your runnable, then AWS Elastic Beanstalk will take it from there. \n \nEg: for apps running on the JVM (Scala/Java/Kotlin) a Zip with the jar inside would suffice, for apps running in a Docker container, a Zip with the DockerFile would be enough. \n\n\n## Prepare your deployment target\nActually, there are 2 options to build your target. \n\nEither you create a DockerFile from this @ref:[Docker image](../install/get-otoroshi.md#from-docker), build a zip, and do all the Otoroshi custom configuration using ENVs.\n\nOr you download the @ref:[otoroshi.jar](../install/get-otoroshi.md#from-jar-file), do all the Otoroshi custom configuration using your own otoroshi.conf, and create a DockerFile that runs the jar using your otoroshi.conf. \n\nFor the second option your DockerFile would look like this :\n\n```dockerfile\nFROM openjdk:11\nVOLUME /tmp\nEXPOSE 8080\nADD otoroshi.jar otoroshi.jar\nADD otoroshi.conf otoroshi.conf\nRUN sh -c 'touch /otoroshi.jar'\nENV JAVA_OPTS=\"\"\nENTRYPOINT [ \"sh\", \"-c\", \"java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dconfig.file=/otoroshi.conf -jar /otoroshi.jar\" ]\n``` \n \nI'd recommend the second option.\n \nNow Zip your target (Jar + Conf + DockerFile) and get ready for deployment. \n\n## Create an Otoroshi instance on AWS Elastic Beanstalk\nFirst, go to [AWS Elastic Beanstalk Console](https://eu-west-3.console.aws.amazon.com/elasticbeanstalk/home?region=eu-west-3#/welcome), don't forget to sign in and make sure that you are in the good region (eg : eu-west-3 for Paris).\n\nHit **Get started** \n\n@@@ div { .centered-img }\n\n@@@\n\nSpecify the **Application name** of your application, Otoroshi for example.\n\n@@@ div { .centered-img }\n\n@@@\n \nChoose the **Platform** of the application you want to create, in your case use Docker.\n\nFor **Application code** choose **Upload your code** then hit **Upload**.\n\n@@@ div { .centered-img }\n\n@@@\n\nBrowse the zip created in the [previous section](#prepare-your-deployment-target) from your machine. \n\nAs you can see in the image above, you can also choose an S3 location, you can imagine that at the end of your build pipeline you upload your Zip to S3, and then get it from there (I wouldn't recommend that though).\n \nWhen the upload is done, hit **Configure more options**.\n \n@@@ div { .centered-img }\n\n@@@ \n \nRight now an AWS Elastic Beanstalk application has been created, and by default an environment named Otoroshi-env is being created as well.\n\nAWS Elastic Beanstalk can manage multiple environments of the same application, for instance environments can be (prod, preprod, expriments...). \n\nOtoroshi is a bit particular, it doesn't make much sense to have multiple environments, since Otoroshi will handle all the requests from/to backend services regardless of the environment. \n \nAs you see in the image above, we are now configuring the Otoroshi-env, the one and only environment of Otoroshi.\n \nFor **Configuration presets**, choose custom configuration, now you have a load balancer for your environment with the capacity of at least one instance and at most four.\nI'd recommend at least 2 instances, to change that, on the **Capacity** card hit **Modify**. \n\n@@@ div { .centered-img }\n\n@@@\n\nChange the **Instances** to min 2, max 4 then hit **Save**. For the **Scaling triggers**, I'd keep the default values, but know that you can edit the capacity config any time you want, it only costs a redeploy, which will be done automatically by the way.\n \nInstances size is by default t2.micro, which is a bit small for running Otoroshi, I'd recommend a t2.medium. \nOn the **Instances** card hit **Modify**.\n\n@@@ div { .centered-img }\n\n@@@\n\nFor **Instance type** choose t2.medium, then hit **Save**, no need to change the volume size, unless you have a lot of http call faults, which means a lot more logs, in that case the default volume size may not be enough.\n\nThe default environment created for Otoroshi, for instance Otoroshi-env, is a web server environment which fits in your case, but the thing is that on AWS Elastic Beanstalk by default a web server environment for a docker-based application, runs behind an Nginx proxy.\nWe have to remove that proxy. So on the **Software** card hit **Modify**.\n \n@@@ div { .centered-img }\n\n@@@ \n \nFor **Proxy server** choose None then hit **Save**.\n\nAlso note that you can set Envs for Otoroshi in same page (see image below). \n\n@@@ div { .centered-img }\n\n@@@ \n\nTo finalise the creation process, hit **Create app** on the bottom right.\n\nThe Otoroshi app is now created, and it's running which is cool, but we still don't have neither a **datastore** nor **https**.\n \n## Create an Otoroshi datastore on AWS ElastiCache\n\nBy default Otoroshi uses non persistent memory to store it's data, Otoroshi supports many kinds of datastores. In this section we will be covering Redis datastore. \n\nBefore starting, using a datastore hosted by AWS is not at all mandatory, feel free to use your own if you like, but if you want to learn more about ElastiCache, this section may interest you, otherwise you can skip it.\n\nGo to [AWS ElastiCache](https://eu-west-3.console.aws.amazon.com/elasticache/home?region=eu-west-3#) and hit **Get Started Now**.\n\n@@@ div { .centered-img }\n\n@@@ \n\nFor **Cluster engine** keep Redis.\n\nChoose a **Name** for your datastore, for instance otoroshi-datastore.\n\nYou can keep all the other default values and hit **Create** on the bottom right of the page.\n\nOnce your Redis Cluster is created, it would look like the image below.\n\n@@@ div { .centered-img }\n\n@@@ \n\n\nFor applications in the same security group as your cluster, redis cluster is accessible via the **Primary Endpoint**. Don't worry the default security group is fine, you don't need any configuration to access the cluster from Otoroshi.\n\nTo make Otoroshi use the created cluster, you can either use Envs `APP_STORAGE=redis`, `REDIS_HOST` and `REDIS_PORT`, or set `otoroshi.storage=redis`, `otoroshi.redis.host` and `otoroshi.redis.port` in your otoroshi.conf.\n\n## Create SSL certificate and configure your domain\n\nOtoroshi has now a datastore, but not yet ready for use. \n\nIn order to get it ready you need to :\n\n* Configure Otoroshi with your domain \n* Create a wildcard SSL certificate for your domain\n* Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate \n* Configure your DNS to redirect all traffic on your domain to Otoroshi \n \n### Configure Otoroshi with your domain\n\nYou can use ENVs or you can use a custom otoroshi.conf in your Docker container.\n\nFor the second option your otoroshi.conf would look like this :\n\n``` \n include \"application.conf\"\n http.port = 8080\n app {\n env = \"prod\"\n domain = \"mysubdomain.oto.tools\"\n rootScheme = \"https\"\n snowflake {\n seed = 0\n }\n events {\n maxSize = 1000\n }\n backoffice {\n subdomain = \"otoroshi\"\n session {\n exp = 86400000\n }\n }\n \n storage = \"redis\"\n redis {\n host=\"myredishost\"\n port=myredisport\n }\n \n privateapps {\n subdomain = \"privateapps\"\n }\n \n adminapi {\n targetSubdomain = \"otoroshi-admin-internal-api\"\n exposedSubdomain = \"otoroshi-api\"\n defaultValues {\n backOfficeGroupId = \"admin-api-group\"\n backOfficeApiKeyClientId = \"admin-client-id\"\n backOfficeApiKeyClientSecret = \"admin-client-secret\"\n backOfficeServiceId = \"admin-api-service\"\n }\n proxy {\n https = true\n local = false\n }\n }\n claim {\n sharedKey = \"myclaimsharedkey\"\n }\n }\n \n play.http {\n session {\n secure = false\n httpOnly = true\n maxAge = 2147483646\n domain = \".mysubdomain.oto.tools\"\n cookieName = \"oto-sess\"\n }\n }\n``` \n\n### Create a wildcard SSL certificate for your domain\n\nGo to [AWS Certificate Manager](https://eu-west-3.console.aws.amazon.com/acm/home?region=eu-west-3#/firstrun).\n\nBelow **Provision certificates** hit **Get started**.\n\n@@@ div { .centered-img }\n\n@@@ \n \nKeep the default selected value **Request a public certificate** and hit **Request a certificate**.\n \n@@@ div { .centered-img }\n\n@@@ \n\nPut your **Domain name**, use *. for wildcard, for instance *\\*.mysubdomain.oto.tools*, then hit **Next**.\n\n@@@ div { .centered-img }\n\n@@@ \n\nYou can choose between **Email validation** and **DNS validation**, I'd recommend **DNS validation**, then hit **Review**. \n \n@@@ div { .centered-img }\n\n@@@ \n \nVerify that you did put the right **Domain name** then hit **Confirm and request**. \n\n@@@ div { .centered-img }\n\n@@@\n \nAs you see in the image above, to let Amazon do the validation you have to add the `CNAME` record to your DNS configuration. Normally this operation takes around one day.\n \n### Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate \n\nOnce the certificate is validated, you need to modify the configuration of Otoroshi-env to add the SSL certificate for HTTPS. \nFor that you need to go to [AWS Elastic Beanstalk applications](https://eu-west-3.console.aws.amazon.com/elasticbeanstalk/home?region=eu-west-3#/applications),\nhit **Otoroshi-env**, then on the left side hit **Configuration**, then on the **Load balancer** card hit **Modify**.\n\n@@@ div { .centered-img }\n\n@@@\n\nIn the **Application Load Balancer** section hit **Add listener**.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the popup as the image above, then hit **Add**. \n\nYou should now be seeing something like this : \n \n@@@ div { .centered-img }\n\n@@@ \n \n \nMake sure that your listener is enabled, and on the bottom right of the page hit **Apply**.\n\nNow you have **https**, so let's use Otoroshi.\n\n### Configure your DNS to redirect all traffic on your domain to Otoroshi\n \nIt's actually pretty simple, you just need to add a `CNAME` record to your DNS configuration, that redirects *\\*.mysubdomain.oto.tools* to the DNS name of Otoroshi's load balancer.\n\nTo find the DNS name of Otoroshi's load balancer go to [AWS Ec2](https://eu-west-3.console.aws.amazon.com/ec2/v2/home?region=eu-west-3#LoadBalancers:tag:elasticbeanstalk:environment-name=Otoroshi-env;sort=loadBalancerName)\n\nYou would find something like this : \n \n@@@ div { .centered-img }\n\n@@@ \n\nThere is your DNS name, so add your `CNAME` record. \n \nOnce all these steps are done, the AWS Elastic Beanstalk Otoroshi instance, would now be handling all the requests on your domain. ;) \n" - }, - { - "name": "clever-cloud.md", - "id": "/deploy/clever-cloud.md", - "url": "/deploy/clever-cloud.html", - "title": "Clever-Cloud", - "content": "# Clever-Cloud\n\nNow you want to use Otoroshi on Clever Cloud. Otoroshi has been designed and created to run on Clever Cloud and a lot of choices were made because of how Clever Cloud works.\n\n## Create an Otoroshi instance on CleverCloud\n\nIf you want to customize the configuration @ref:[use env. variables](../install/setup-otoroshi.md#configuration-with-env-variables), you can use [the example provided below](#example-of-clevercloud-env-variables)\n\nCreate a new CleverCloud app based on a clevercloud git repo (not empty) or a github project of your own (not empty).\n\n@@@ div { .centered-img }\n\n@@@\n\nThen choose what kind of app your want to create, for Otoroshi, choose `Java + Jar`\n\n@@@ div { .centered-img }\n\n@@@\n\nNext, set up choose instance size and auto-scalling. Otoroshi can run on small instances, especially if you just want to test it.\n\n@@@ div { .centered-img }\n\n@@@\n\nFinally, choose a name for your app\n\n@@@ div { .centered-img }\n\n@@@\n\nNow you just need to customize environnment variables\n\nat this point, you can also add other env. variables to configure Otoroshi like in [the example provided below](#example-of-clevercloud-env-variables)\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also use expert mode :\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, your app is ready, don't forget to add a custom domains name on the CleverCloud app matching the Otoroshi app domain. \n\n## Example of CleverCloud env. variables\n\nYou can add more env variables to customize your Otoroshi instance like the following. Use the expert mode to copy/paste all the values in one shot. If you want an real datastore, create a redis addon on clevercloud, link it to your otoroshi app and change the `APP_STORAGE` variable to `redis`\n\n
\n\n
\n```\nADMIN_API_CLIENT_ID=xxxx\nADMIN_API_CLIENT_SECRET=xxxxx\nADMIN_API_GROUP=xxxxxx\nADMIN_API_SERVICE_ID=xxxxxxx\nCLAIM_SHAREDKEY=xxxxxxx\nOTOROSHI_INITIAL_ADMIN_LOGIN=youremailaddress\nOTOROSHI_INITIAL_ADMIN_PASSWORD=yourpassword\nPLAY_CRYPTO_SECRET=xxxxxx\nSESSION_NAME=oto-session\nAPP_DOMAIN=yourdomain.tech\nAPP_ENV=prod\nAPP_STORAGE=inmemory\nAPP_ROOT_SCHEME=https\nCC_PRE_BUILD_HOOK=curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/${latest_otoroshi_version}/otoroshi.jar'\nCC_JAR_PATH=./otoroshi.jar\nCC_JAVA_VERSION=11\nPORT=8080\nSESSION_DOMAIN=.yourdomain.tech\nSESSION_MAX_AGE=604800000\nSESSION_SECURE_ONLY=true\nUSER_AGENT=otoroshi\nMAX_EVENTS_SIZE=1\nWEBHOOK_SIZE=100\nAPP_BACKOFFICE_SESSION_EXP=86400000\nAPP_PRIVATEAPPS_SESSION_EXP=86400000\nENABLE_METRICS=true\nOTOROSHI_ANALYTICS_PRESSURE_ENABLED=true\nUSE_CACHE=true\n```\n
" - }, - { - "name": "clustering.md", - "id": "/deploy/clustering.md", - "url": "/deploy/clustering.html", - "title": "Otoroshi clustering", - "content": "# Otoroshi clustering\n\nOtoroshi can work as a cluster by default as you can spin many Otoroshi servers using the same datastore or datastore cluster. In that case any instance is capable of serving services, Otoroshi admin UI, Otoroshi admin API, etc.\n\nBut sometimes, this is not enough. So Otoroshi provides an additional clustering model named `Leader / Workers` where there is a leader cluster ([control plane](https://en.wikipedia.org/wiki/Control_plane)), composed of Otoroshi instances backed by a datastore like Redis, PostgreSQL or Cassandra, that is in charge of all `writes` to the datastore through Otoroshi admin UI and API, and a worker cluster ([data plane](https://en.wikipedia.org/wiki/Forwarding_plane)) composed of horizontally scalable Otoroshi instances, backed by a super fast in memory datastore, with the sole purpose of routing traffic to your services based on data synced from the leader cluster. With this distributed Otoroshi version, you can reach your goals of high availability, scalability and security.\n\nOtoroshi clustering only uses http internally (right now) to make communications between leaders and workers instances so it is fully compatible with PaaS providers like [Clever-Cloud](https://www.clever-cloud.com/en/) that only provide one external port for http traffic.\n\n@@@ div { .centered-img }\n\n\n*Fig. 1: Simplified view*\n@@@\n\n@@@ div { .centered-img }\n\n\n*Fig. 2: Deployment view*\n@@@\n\n## Cluster configuration\n\n```hocon\notoroshi {\n cluster {\n mode = \"leader\" # can be \"off\", \"leader\", \"worker\"\n compression = 4 # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9\n leader {\n name = ${?CLUSTER_LEADER_NAME} # name of the instance, if none, it will be generated\n urls = [\"http://127.0.0.1:8080\"] # urls to contact the leader cluster\n host = \"otoroshi-api.oto.tools\" # host of the otoroshi api in the leader cluster\n clientId = \"apikey-id\" # otoroshi api client id\n clientSecret = \"secret\" # otoroshi api client secret\n cacheStateFor = 4000 # state is cached during (ms)\n }\n worker {\n name = ${?CLUSTER_WORKER_NAME} # name of the instance, if none, it will be generated\n retries = 3 # number of retries when calling leader cluster\n timeout = 2000 # timeout when calling leader cluster\n state {\n retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on state sync\n pollEvery = 10000 # interval of time (ms) between 2 state sync\n timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on state sync\n }\n quotas {\n retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on quotas sync\n pushEvery = 2000 # interval of time (ms) between 2 quotas sync\n timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on quotas sync\n }\n }\n }\n}\n```\n\nyou can also use many env. variables to configure Otoroshi cluster\n\n```hocon\notoroshi {\n cluster {\n mode = ${?CLUSTER_MODE}\n compression = ${?CLUSTER_COMPRESSION}\n leader {\n name = ${?CLUSTER_LEADER_NAME}\n host = ${?CLUSTER_LEADER_HOST}\n url = ${?CLUSTER_LEADER_URL}\n clientId = ${?CLUSTER_LEADER_CLIENT_ID}\n clientSecret = ${?CLUSTER_LEADER_CLIENT_SECRET}\n groupingBy = ${?CLUSTER_LEADER_GROUP_BY}\n cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR}\n stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH}\n }\n worker {\n name = ${?CLUSTER_WORKER_NAME}\n retries = ${?CLUSTER_WORKER_RETRIES}\n timeout = ${?CLUSTER_WORKER_TIMEOUT}\n state {\n retries = ${?CLUSTER_WORKER_STATE_RETRIES}\n pollEvery = ${?CLUSTER_WORKER_POLL_EVERY}\n timeout = ${?CLUSTER_WORKER_POLL_TIMEOUT}\n }\n quotas {\n retries = ${?CLUSTER_WORKER_QUOTAS_RETRIES}\n pushEvery = ${?CLUSTER_WORKER_PUSH_EVERY}\n timeout = ${?CLUSTER_WORKER_PUSH_TIMEOUT}\n }\n }\n }\n}\n```\n\n@@@ warning\nYou **should** use HTTPS exposition for the Otoroshi API that will be used for data sync as sensitive informations are exchanged between control plane and data plane.\n@@@\n\n@@@ warning\nYou **must** have the same cluster configuration on every Otoroshi instance (worker/leader) with only names and mode changed for each instance. Some things in leader/worker are computed using configuration of their counterpart worker/leader.\n@@@\n\n## Cluster UI\n\nOnce an Otoroshi instance is launcher as cluster Leader, a new row of live metrics tile will be available on the home page of Otoroshi admin UI.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can also access a more detailed view of the cluster at `Settings (cog icon) / Cluster View`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Run examples\n\nfor leader \n\n```sh\njava -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar\n```\n\nfor worker\n\n```sh\njava -Dhttp.port=8092 -Dhttps.port=9092 -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0=http://127.0.0.1:8091 -jar otoroshi.jar\n```\n\n## Setup a cluster by example\n\nif you want to see how to setup an otoroshi cluster, just check @ref:[the clustering tutorial](../how-to-s/setup-otoroshi-cluster.md)" - }, - { - "name": "index.md", - "id": "/deploy/index.md", - "url": "/deploy/index.html", - "title": "Deploy to production", - "content": "# Deploy to production\n\nNow it's time to deploy Otoroshi in production, in this chapter we will see what kind of things you can do.\n\nOtoroshi can run wherever you want, even on a raspberry pi (Cluster^^) ;)\n\n@@@div { .plugin .platform }\n## Clever Cloud\n\nOtoroshi provides an integration to create easily services based on application deployed on your Clever Cloud account.\n\n\n@ref:[Documentation](./clever-cloud.md)\n@@@\n\n@@@div { .plugin .platform } \n## Kubernetes\nStarting at version 1.5.0, Otoroshi provides a native Kubernetes support.\n\n\n\n@ref:[Documentation](./kubernetes.md)\n@@@\n\n@@@div { .plugin .platform } \n## AWS Elastic Beanstalk\n\nRun Otoroshi on AWS Elastic Beanstalk\n\n\n\n@ref:[Tutorial](./aws.md)\n@@@\n\n@@@div { .plugin .platform } \n## Amazon ECS\n\nDeploy the Otoroshi Docker image using Amazon Elastic Container Service\n\n\n\n@link:[Tutorial](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n\n@@@\n\n@@@div { .plugin .platform }\n## GCE\n\nDeploy the Docker image using Google Compute Engine container integration\n\n\n\n@link:[Documentation](https://cloud.google.com/compute/docs/containers/deploying-containers)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n\n@@@\n\n@@@div { .plugin .platform } \n## Azure\n\nDeploy the Docker image using Azure Container Service\n\n\n\n@link:[Documentation](https://azure.microsoft.com/en-us/services/container-service/)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker) \n@@@\n\n@@@div { .plugin .platform } \n## Heroku\n\nDeploy the Docker image using Docker integration\n\n\n\n@link:[Documentation](https://devcenter.heroku.com/articles/container-registry-and-runtime)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n@@@\n\n@@@div { .plugin .platform } \n## CloudFoundry\n\nDeploy the Docker image using -Docker integration\n\n\n\n@link:[Documentation](https://docs.cloudfoundry.org/adminguide/docker.html)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n@@@\n\n@@@div { .plugin .platform .platform-actions-column } \n## Your own infrastructure\n\nAs Otoroshi is a Play Framework application, you can read the doc about putting a `Play` app in production.\n\nDownload the latest Otoroshi distribution, unzip it, customize it and run it.\n\n@link:[Play Framework](https://www.playframework.com)\n@link:[Production Configuration](https://www.playframework.com/documentation/2.6.x/ProductionConfiguration)\n@ref:[Otoroshi distribution](../install/get-otoroshi.md#from-zip)\n@@@\n\n@@@div { .break }\n## Scaling and clustering in production\n@@@\n\n\n@@@div { .plugin .platform .dark-platform } \n## Clustering\n\nDeploy Otoroshi as a cluster of leaders and workers.\n\n\n@ref:[Documentation](./clustering.md)\n@@@\n\n@@@div { .plugin .platform .dark-platform } \n## Scaling Otoroshi\n\nOtoroshi is designed to be reasonably easy to scale and be highly available.\n\n\n@ref:[Documentation](./scaling.md) \n@@@\n\n@@@ index\n\n* [Clustering](./clustering.md)\n* [Kubernetes](./kubernetes.md)\n* [Clever Cloud](./clever-cloud.md)\n* [AWS - Elastic Beanstalk](./aws.md)\n* [Scaling](./scaling.md) \n\n@@@\n" - }, - { - "name": "kubernetes.md", - "id": "/deploy/kubernetes.md", - "url": "/deploy/kubernetes.html", - "title": "Kubernetes", - "content": "# Kubernetes\n\nStarting at version 1.5.0, Otoroshi provides a native Kubernetes support. Multiple otoroshi jobs (that are actually kubernetes controllers) are provided in order to\n\n- sync kubernetes secrets of type `kubernetes.io/tls` to otoroshi certificates\n- act as a standard ingress controller (supporting `Ingress` objects)\n- provide Custom Resource Definitions (CRDs) to manage Otoroshi entities from Kubernetes and act as an ingress controller with its own resources\n\n## Installing otoroshi on your kubernetes cluster\n\n@@@ warning\nYou need to have cluster admin privileges to install otoroshi and its service account, role mapping and CRDs on a kubernetes cluster. We also advise you to create a dedicated namespace (you can name it `otoroshi` for example) to install otoroshi\n@@@\n\nIf you want to deploy otoroshi into your kubernetes cluster, you can download the deployment descriptors from https://github.com/MAIF/otoroshi/tree/master/kubernetes and use kustomize to create your own overlay.\n\nYou can also create a `kustomization.yaml` file with a remote base\n\n```yaml\nbases:\n- github.com/MAIF/otoroshi/kubernetes/kustomize/overlays/simple/?ref=v1.5.11\n```\n\nThen deploy it with `kubectl apply -k ./overlays/myoverlay`. \n\nYou can also use Helm to deploy a simple otoroshi cluster on your kubernetes cluster\n\n```sh\nhelm repo add otoroshi https://maif.github.io/otoroshi/helm\nhelm install my-otoroshi otoroshi/otoroshi\n```\n\nBelow, you will find example of deployment. Do not hesitate to adapt them to your needs. Those descriptors have value placeholders that you will need to replace with actual values like \n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: ${domain}\n```\n\nyou will have to edit it to make it look like\n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: 'apis.my.domain'\n```\n\nif you don't want to use placeholders and environment variables, you can create a secret containing the configuration file of otoroshi\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: otoroshi-config\ntype: Opaque\nstringData:\n oto.conf: >\n include \"application.conf\"\n app {\n storage = \"redis\"\n domain = \"apis.my.domain\"\n }\n```\n\nand mount it in the otoroshi container\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: otoroshi-deployment\nspec:\n selector:\n matchLabels:\n run: otoroshi-deployment\n template:\n metadata:\n labels:\n run: otoroshi-deployment\n spec:\n serviceAccountName: otoroshi-admin-user\n terminationGracePeriodSeconds: 60\n hostNetwork: false\n containers:\n - image: maif/otoroshi:1.5.11\n imagePullPolicy: IfNotPresent\n name: otoroshi\n args: ['-Dconfig.file=/usr/app/otoroshi/conf/oto.conf']\n ports:\n - containerPort: 8080\n name: \"http\"\n protocol: TCP\n - containerPort: 8443\n name: \"https\"\n protocol: TCP\n volumeMounts:\n - name: otoroshi-config\n mountPath: \"/usr/app/otoroshi/conf\"\n readOnly: true\n volumes:\n - name: otoroshi-config\n secret:\n secretName: otoroshi-config\n ...\n```\n\nYou can also create several secrets for each placeholder, mount them to the otoroshi container then use their file path as value\n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: 'file:///the/path/of/the/secret/file'\n```\n\nyou can use the same trick in the config. file itself\n\n### Note on bare metal kubernetes cluster installation\n\n@@@ note\nBare metal kubernetes clusters don't come with support for external loadbalancers (service of type `LoadBalancer`). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like [MetalLB](https://metallb.universe.tf/) that provide software `LoadBalancer` services to bare metal clusters or you can use and customize examples below.\n@@@\n\n@@@ warning\nWe don't recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.\n@@@\n\n### Common manifests\n\nthe following manifests are always needed. They create otoroshi CRDs, tokens, role, etc. Redis deployment is not mandatory, it's just an example. You can use your own existing setup.\n\nrbac.yaml\n: @@snip [rbac.yaml](../snippets/kubernetes/kustomize/base/rbac.yaml) \n\ncrds.yaml\n: @@snip [crds.yaml](../snippets/kubernetes/kustomize/base/crds.yaml) \n\nredis.yaml\n: @@snip [redis.yaml](../snippets/kubernetes/kustomize/base/redis.yaml) \n\n\n### Deploy a simple otoroshi instanciation on a cloud provider managed kubernetes cluster\n\nHere we have 2 replicas connected to the same redis instance. Nothing fancy. We use a service of type `LoadBalancer` to expose otoroshi to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the `LoadBalancer` external `CNAME` (see the example below)\n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple/deployment.yaml) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple/dns.example) \n\n### Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster\n\nHere we have 2 replicas connected to the same redis instance. Nothing fancy. The otoroshi instance are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple-baremetal/deployment.yaml) \n\nhaproxy.example\n: @@snip [haproxy.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/haproxy.example) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/dns.example) \n\n\n### Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster using a DaemonSet\n\nHere we have one otoroshi instance on each kubernetes node (with the `otoroshi-kind: instance` label) with redis persistance. The otoroshi instances are exposed as `hostPort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/deployment.yaml) \n\nhaproxy.example\n: @@snip [haproxy.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/haproxy.example) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/dns.example) \n\n### Deploy an otoroshi cluster on a cloud provider managed kubernetes cluster\n\nHere we have 2 replicas of an otoroshi leader connected to a redis instance and 2 replicas of an otoroshi worker connected to the leader. We use a service of type `LoadBalancer` to expose otoroshi leader/worker to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the `LoadBalancer` external `CNAME` (see the example below)\n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster/deployment.yaml) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster/dns.example) \n\n### Deploy an otoroshi cluster on a bare metal kubernetes cluster\n\nHere we have 2 replicas of otoroshi leader connected to the same redis instance and 2 replicas for otoroshi worker. The otoroshi instances are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/deployment.yaml) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/dns.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/dns.example) \n\n### Deploy an otoroshi cluster on a bare metal kubernetes cluster using DaemonSet\n\nHere we have 1 otoroshi leader instance on each kubernetes node (with the `otoroshi-kind: leader` label) connected to the same redis instance and 1 otoroshi worker instance on each kubernetes node (with the `otoroshi-kind: worker` label). The otoroshi instances are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/deployment.yaml) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/dns.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/dns.example) \n\n## Using Otoroshi as an Ingress Controller\n\nIf you want to use Otoroshi as an [Ingress Controller](https://kubernetes.io/fr/docs/concepts/services-networking/ingress/), just go to the danger zone, and in `Global scripts` add the job named `Kubernetes Ingress Controller`.\n\nThen add the following configuration for the job (with your own tweaks of course)\n\n```json\n{\n \"KubernetesConfig\": {\n \"enabled\": true,\n \"endpoint\": \"https://127.0.0.1:6443\",\n \"token\": \"eyJhbGciOiJSUzI....F463SrpOehQRaQ\",\n \"namespaces\": [\n \"*\"\n ]\n }\n}\n```\n\nthe configuration can have the following values \n\n```javascript\n{\n \"KubernetesConfig\": {\n \"endpoint\": \"https://127.0.0.1:6443\", // the endpoint to talk to the kubernetes api, optional\n \"token\": \"xxxx\", // the bearer token to talk to the kubernetes api, optional\n \"userPassword\": \"user:password\", // the user password tuple to talk to the kubernetes api, optional\n \"caCert\": \"/etc/ca.cert\", // the ca cert file path to talk to the kubernetes api, optional\n \"trust\": false, // trust any cert to talk to the kubernetes api, optional\n \"namespaces\": [\"*\"], // the watched namespaces\n \"labels\": [\"label\"], // the watched namespaces\n \"ingressClasses\": [\"otoroshi\"], // the watched kubernetes.io/ingress.class annotations, can be *\n \"defaultGroup\": \"default\", // the group to put services in otoroshi\n \"ingresses\": true, // sync ingresses\n \"crds\": false, // sync crds\n \"kubeLeader\": false, // delegate leader election to kubernetes, to know where the sync job should run\n \"restartDependantDeployments\": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments\n \"templates\": { // template for entities that will be merged with kubernetes entities. can be \"default\" to use otoroshi default templates\n \"service-group\": {},\n \"service-descriptor\": {},\n \"apikeys\": {},\n \"global-config\": {},\n \"jwt-verifier\": {},\n \"tcp-service\": {},\n \"certificate\": {},\n \"auth-module\": {},\n \"data-exporter\": {},\n \"script\": {},\n \"organization\": {},\n \"team\": {},\n \"data-exporter\": {}\n }\n }\n}\n```\n\nIf `endpoint` is not defined, Otoroshi will try to get it from `$KUBERNETES_SERVICE_HOST` and `$KUBERNETES_SERVICE_PORT`.\nIf `token` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/token`.\nIf `caCert` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`.\nIf `$KUBECONFIG` is defined, `endpoint`, `token` and `caCert` will be read from the current context of the file referenced by it.\n\nNow you can deploy your first service ;)\n\n### Deploy an ingress route\n\nnow let's say you want to deploy an http service and route to the outside world through otoroshi\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-app-deployment\nspec:\n selector:\n matchLabels:\n run: http-app-deployment\n replicas: 1\n template:\n metadata:\n labels:\n run: http-app-deployment\n spec:\n containers:\n - image: kennethreitz/httpbin\n imagePullPolicy: IfNotPresent\n name: otoroshi\n ports:\n - containerPort: 80\n name: \"http\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: http-app-service\nspec:\n ports:\n - port: 8080\n targetPort: http\n name: http\n selector:\n run: http-app-deployment\n---\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\n annotations:\n kubernetes.io/ingress.class: otoroshi\nspec:\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\nonce deployed, otoroshi will sync with kubernetes and create the corresponding service to route your app. You will be able to access your app with\n\n```sh\ncurl -X GET https://httpapp.foo.bar/get\n```\n\n### Support for Ingress Classes\n\nSince Kubernetes 1.18, you can use `IngressClass` type of manifest to specify which ingress controller you want to use for a deployment (https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#extended-configuration-with-ingress-classes). Otoroshi is fully compatible with this new manifest `kind`. To use it, configure the Ingress job to match your controller\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"ingressClasses\": [\"otoroshi.io/ingress-controller\"],\n ...\n }\n}\n```\n\nthen you have to deploy an `IngressClass` to declare Otoroshi as an ingress controller\n\n```yaml\napiVersion: \"networking.k8s.io/v1beta1\"\nkind: \"IngressClass\"\nmetadata:\n name: \"otoroshi-ingress-controller\"\nspec:\n controller: \"otoroshi.io/ingress-controller\"\n parameters:\n apiGroup: \"proxy.otoroshi.io/v1alpha\"\n kind: \"IngressParameters\"\n name: \"otoroshi-ingress-controller\"\n```\n\nand use it in your `Ingress`\n\n```yaml\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\nspec:\n ingressClassName: otoroshi-ingress-controller\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\n### Use multiple ingress controllers\n\nIt is of course possible to use multiple ingress controller at the same time (https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#using-multiple-ingress-controllers) using the annotation `kubernetes.io/ingress.class`. By default, otoroshi reacts to the class `otoroshi`, but you can make it the default ingress controller with the following config\n\n```json\n{\n \"KubernetesConfig\": {\n ...\n \"ingressClass\": \"*\",\n ...\n }\n}\n```\n\n### Supported annotations\n\nif you need to customize the service descriptor behind an ingress rule, you can use some annotations. If you need better customisation, just go to the CRDs part. The following annotations are supported :\n\n- `ingress.otoroshi.io/groups`\n- `ingress.otoroshi.io/group`\n- `ingress.otoroshi.io/groupId`\n- `ingress.otoroshi.io/name`\n- `ingress.otoroshi.io/targetsLoadBalancing`\n- `ingress.otoroshi.io/stripPath`\n- `ingress.otoroshi.io/enabled`\n- `ingress.otoroshi.io/userFacing`\n- `ingress.otoroshi.io/privateApp`\n- `ingress.otoroshi.io/forceHttps`\n- `ingress.otoroshi.io/maintenanceMode`\n- `ingress.otoroshi.io/buildMode`\n- `ingress.otoroshi.io/strictlyPrivate`\n- `ingress.otoroshi.io/sendOtoroshiHeadersBack`\n- `ingress.otoroshi.io/readOnly`\n- `ingress.otoroshi.io/xForwardedHeaders`\n- `ingress.otoroshi.io/overrideHost`\n- `ingress.otoroshi.io/allowHttp10`\n- `ingress.otoroshi.io/logAnalyticsOnServer`\n- `ingress.otoroshi.io/useAkkaHttpClient`\n- `ingress.otoroshi.io/useNewWSClient`\n- `ingress.otoroshi.io/tcpUdpTunneling`\n- `ingress.otoroshi.io/detectApiKeySooner`\n- `ingress.otoroshi.io/letsEncrypt`\n- `ingress.otoroshi.io/publicPatterns`\n- `ingress.otoroshi.io/privatePatterns`\n- `ingress.otoroshi.io/additionalHeaders`\n- `ingress.otoroshi.io/additionalHeadersOut`\n- `ingress.otoroshi.io/missingOnlyHeadersIn`\n- `ingress.otoroshi.io/missingOnlyHeadersOut`\n- `ingress.otoroshi.io/removeHeadersIn`\n- `ingress.otoroshi.io/removeHeadersOut`\n- `ingress.otoroshi.io/headersVerification`\n- `ingress.otoroshi.io/matchingHeaders`\n- `ingress.otoroshi.io/ipFiltering.whitelist`\n- `ingress.otoroshi.io/ipFiltering.blacklist`\n- `ingress.otoroshi.io/api.exposeApi`\n- `ingress.otoroshi.io/api.openApiDescriptorUrl`\n- `ingress.otoroshi.io/healthCheck.enabled`\n- `ingress.otoroshi.io/healthCheck.url`\n- `ingress.otoroshi.io/jwtVerifier.ids`\n- `ingress.otoroshi.io/jwtVerifier.enabled`\n- `ingress.otoroshi.io/jwtVerifier.excludedPatterns`\n- `ingress.otoroshi.io/authConfigRef`\n- `ingress.otoroshi.io/redirection.enabled`\n- `ingress.otoroshi.io/redirection.code`\n- `ingress.otoroshi.io/redirection.to`\n- `ingress.otoroshi.io/clientValidatorRef`\n- `ingress.otoroshi.io/transformerRefs`\n- `ingress.otoroshi.io/transformerConfig`\n- `ingress.otoroshi.io/accessValidator.enabled`\n- `ingress.otoroshi.io/accessValidator.excludedPatterns`\n- `ingress.otoroshi.io/accessValidator.refs`\n- `ingress.otoroshi.io/accessValidator.config`\n- `ingress.otoroshi.io/preRouting.enabled`\n- `ingress.otoroshi.io/preRouting.excludedPatterns`\n- `ingress.otoroshi.io/preRouting.refs`\n- `ingress.otoroshi.io/preRouting.config`\n- `ingress.otoroshi.io/issueCert`\n- `ingress.otoroshi.io/issueCertCA`\n- `ingress.otoroshi.io/gzip.enabled`\n- `ingress.otoroshi.io/gzip.excludedPatterns`\n- `ingress.otoroshi.io/gzip.whiteList`\n- `ingress.otoroshi.io/gzip.blackList`\n- `ingress.otoroshi.io/gzip.bufferSize`\n- `ingress.otoroshi.io/gzip.chunkedThreshold`\n- `ingress.otoroshi.io/gzip.compressionLevel`\n- `ingress.otoroshi.io/cors.enabled`\n- `ingress.otoroshi.io/cors.allowOrigin`\n- `ingress.otoroshi.io/cors.exposeHeaders`\n- `ingress.otoroshi.io/cors.allowHeaders`\n- `ingress.otoroshi.io/cors.allowMethods`\n- `ingress.otoroshi.io/cors.excludedPatterns`\n- `ingress.otoroshi.io/cors.maxAge`\n- `ingress.otoroshi.io/cors.allowCredentials`\n- `ingress.otoroshi.io/clientConfig.useCircuitBreaker`\n- `ingress.otoroshi.io/clientConfig.retries`\n- `ingress.otoroshi.io/clientConfig.maxErrors`\n- `ingress.otoroshi.io/clientConfig.retryInitialDelay`\n- `ingress.otoroshi.io/clientConfig.backoffFactor`\n- `ingress.otoroshi.io/clientConfig.connectionTimeout`\n- `ingress.otoroshi.io/clientConfig.idleTimeout`\n- `ingress.otoroshi.io/clientConfig.callAndStreamTimeout`\n- `ingress.otoroshi.io/clientConfig.callTimeout`\n- `ingress.otoroshi.io/clientConfig.globalTimeout`\n- `ingress.otoroshi.io/clientConfig.sampleInterval`\n- `ingress.otoroshi.io/enforceSecureCommunication`\n- `ingress.otoroshi.io/sendInfoToken`\n- `ingress.otoroshi.io/sendStateChallenge`\n- `ingress.otoroshi.io/secComHeaders.claimRequestName`\n- `ingress.otoroshi.io/secComHeaders.stateRequestName`\n- `ingress.otoroshi.io/secComHeaders.stateResponseName`\n- `ingress.otoroshi.io/secComTtl`\n- `ingress.otoroshi.io/secComVersion`\n- `ingress.otoroshi.io/secComInfoTokenVersion`\n- `ingress.otoroshi.io/secComExcludedPatterns`\n- `ingress.otoroshi.io/secComSettings.size`\n- `ingress.otoroshi.io/secComSettings.secret`\n- `ingress.otoroshi.io/secComSettings.base64`\n- `ingress.otoroshi.io/secComUseSameAlgo`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.size`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.secret`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.base64`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.size`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.secret`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.base64`\n- `ingress.otoroshi.io/secComAlgoInfoToken.size`\n- `ingress.otoroshi.io/secComAlgoInfoToken.secret`\n- `ingress.otoroshi.io/secComAlgoInfoToken.base64`\n- `ingress.otoroshi.io/securityExcludedPatterns`\n\nfor more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html\n\nwith the previous example, the ingress does not define any apikey, so the route is public. If you want to enable apikeys on it, you can deploy the following descriptor\n\n```yaml\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\n annotations:\n kubernetes.io/ingress.class: otoroshi\n ingress.otoroshi.io/group: http-app-group\n ingress.otoroshi.io/forceHttps: 'true'\n ingress.otoroshi.io/sendOtoroshiHeadersBack: 'true'\n ingress.otoroshi.io/overrideHost: 'true'\n ingress.otoroshi.io/allowHttp10: 'false'\n ingress.otoroshi.io/publicPatterns: ''\nspec:\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\nnow you can use an existing apikey in the `http-app-group` to access your app\n\n```sh\ncurl -X GET https://httpapp.foo.bar/get -u existing-apikey-1:secret-1\n```\n\n## Use Otoroshi CRDs for a better/full integration\n\nOtoroshi provides some Custom Resource Definitions for kubernetes in order to manage Otoroshi related entities in kubernetes\n\n- `service-groups`\n- `service-descriptors`\n- `apikeys`\n- `certificates`\n- `global-configs`\n- `jwt-verifiers`\n- `auth-modules`\n- `scripts`\n- `tcp-services`\n- `data-exporters`\n- `admins`\n- `teams`\n- `organizations`\n\nusing CRDs, you will be able to deploy and manager those entities from kubectl or the kubernetes api like\n\n```sh\nsudo kubectl get apikeys --all-namespaces\nsudo kubectl get service-descriptors --all-namespaces\ncurl -X GET \\\n -H 'Authorization: Bearer eyJhbGciOiJSUzI....F463SrpOehQRaQ' \\\n -H 'Accept: application/json' -k \\\n https://127.0.0.1:6443/apis/proxy.otoroshi.io/v1alpha1/apikeys | jq\n```\n\nYou can see this as better `Ingress` resources. Like any `Ingress` resource can define which controller it uses (using the `kubernetes.io/ingress.class` annotation), you can chose another kind of resource instead of `Ingress`. With Otoroshi CRDs you can even define resources like `Certificate`, `Apikey`, `AuthModules`, `JwtVerifier`, etc. It will help you to use all the power of Otoroshi while using the deployment model of kubernetes.\n \n@@@ warning\nwhen using Otoroshi CRDs, Kubernetes becomes the single source of truth for the synced entities. It means that any value in the descriptors deployed will overrides the one in Otoroshi datastore each time it's synced. So be careful if you use the Otoroshi UI or the API, some changes in configuration may be overriden by CRDs sync job.\n@@@\n\n### Resources examples\n\ngroup.yaml\n: @@snip [group.yaml](../snippets/crds/group.yaml) \n\napikey.yaml\n: @@snip [apikey.yaml](../snippets/crds/apikey.yaml) \n\nservice-descriptor.yaml\n: @@snip [service.yaml](../snippets/crds/service-descriptor.yaml) \n\ncertificate.yaml\n: @@snip [cert.yaml](../snippets/crds/certificate.yaml) \n\njwt.yaml\n: @@snip [jwt.yaml](../snippets/crds/jwt.yaml) \n\nauth.yaml\n: @@snip [auth.yaml](../snippets/crds/auth.yaml) \n\norganization.yaml\n: @@snip [orga.yaml](../snippets/crds/organization.yaml) \n\nteam.yaml\n: @@snip [team.yaml](../snippets/crds/team.yaml) \n\n\n### Configuration\n\nTo configure it, just go to the danger zone, and in `Global scripts` add the job named `Kubernetes Otoroshi CRDs Controller`. Then add the following configuration for the job (with your own tweak of course)\n\n```json\n{\n \"KubernetesConfig\": {\n \"enabled\": true,\n \"crds\": true,\n \"endpoint\": \"https://127.0.0.1:6443\",\n \"token\": \"eyJhbGciOiJSUzI....F463SrpOehQRaQ\",\n \"namespaces\": [\n \"*\"\n ]\n }\n}\n```\n\nthe configuration can have the following values \n\n```javascript\n{\n \"KubernetesConfig\": {\n \"endpoint\": \"https://127.0.0.1:6443\", // the endpoint to talk to the kubernetes api, optional\n \"token\": \"xxxx\", // the bearer token to talk to the kubernetes api, optional\n \"userPassword\": \"user:password\", // the user password tuple to talk to the kubernetes api, optional\n \"caCert\": \"/etc/ca.cert\", // the ca cert file path to talk to the kubernetes api, optional\n \"trust\": false, // trust any cert to talk to the kubernetes api, optional\n \"namespaces\": [\"*\"], // the watched namespaces\n \"labels\": [\"label\"], // the watched namespaces\n \"ingressClasses\": [\"otoroshi\"], // the watched kubernetes.io/ingress.class annotations, can be *\n \"defaultGroup\": \"default\", // the group to put services in otoroshi\n \"ingresses\": false, // sync ingresses\n \"crds\": true, // sync crds\n \"kubeLeader\": false, // delegate leader election to kubernetes, to know where the sync job should run\n \"restartDependantDeployments\": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments\n \"templates\": { // template for entities that will be merged with kubernetes entities. can be \"default\" to use otoroshi default templates\n \"service-group\": {},\n \"service-descriptor\": {},\n \"apikeys\": {},\n \"global-config\": {},\n \"jwt-verifier\": {},\n \"tcp-service\": {},\n \"certificate\": {},\n \"auth-module\": {},\n \"data-exporter\": {},\n \"script\": {},\n \"organization\": {},\n \"team\": {},\n \"data-exporter\": {}\n }\n }\n}\n```\n\nIf `endpoint` is not defined, Otoroshi will try to get it from `$KUBERNETES_SERVICE_HOST` and `$KUBERNETES_SERVICE_PORT`.\nIf `token` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/token`.\nIf `caCert` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`.\nIf `$KUBECONFIG` is defined, `endpoint`, `token` and `caCert` will be read from the current context of the file referenced by it.\n\nyou can find a more complete example of the configuration object [here](https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/plugins/jobs/kubernetes/config.scala#L134-L163)\n\n### Note about `apikeys` and `certificates` resources\n\nApikeys and Certificates are a little bit different than the other resources. They have ability to be defined without their secret part, but with an export setting so otoroshi will generate the secret parts and export the apikey or the certificate to kubernetes secret. Then any app will be able to mount them as volumes (see the full example below)\n\nIn those resources you can define \n\n```yaml\nexportSecret: true \nsecretName: the-secret-name\n```\n\nand omit `clientSecret` for apikey or `publicKey`, `privateKey` for certificates. For certificate you will have to provide a `csr` for the certificate in order to generate it\n\n```yaml\ncsr:\n issuer: CN=Otoroshi Root\n hosts: \n - httpapp.foo.bar\n - httpapps.foo.bar\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-front, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n```\n\nwhen apikeys are exported as kubernetes secrets, they will have the type `otoroshi.io/apikey-secret` with values `clientId` and `clientSecret`\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: apikey-1\ntype: otoroshi.io/apikey-secret\ndata:\n clientId: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n clientSecret: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n```\n\nwhen certificates are exported as kubernetes secrets, they will have the type `kubernetes.io/tls` with the standard values `tls.crt` (the full cert chain) and `tls.key` (the private key). For more convenience, they will also have a `cert.crt` value containing the actual certificate without the ca chain and `ca-chain.crt` containing the ca chain without the certificate.\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: certificate-1\ntype: kubernetes.io/tls\ndata:\n tls.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n tls.key: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n cert.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n ca-chain.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA== \n```\n\n## Full CRD example\n\nthen you can deploy the previous example with better configuration level, and using mtls, apikeys, etc\n\nLet say the app looks like :\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\n// here we read the apikey to access http-app-2 from files mounted from secrets\nconst clientId = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientId').toString('utf8')\nconst clientSecret = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientSecret').toString('utf8')\n\nconst backendKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/tls.key').toString('utf8')\nconst backendCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/cert.crt').toString('utf8')\nconst backendCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/ca-chain.crt').toString('utf8')\n\nconst clientKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/tls.key').toString('utf8')\nconst clientCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/cert.crt').toString('utf8')\nconst clientCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/ca-chain.crt').toString('utf8')\n\nfunction callApi2() {\n return new Promise((success, failure) => {\n const options = { \n // using the implicit internal name (*.global.otoroshi.mesh) of the other service descriptor passing through otoroshi\n hostname: 'http-app-service-descriptor-2.global.otoroshi.mesh', \n port: 433, \n path: '/', \n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Otoroshi-Client-Id': clientId,\n 'Otoroshi-Client-Secret': clientSecret,\n },\n cert: clientCert,\n key: clientKey,\n ca: clientCa\n }; \n let data = '';\n const req = https.request(options, (res) => { \n res.on('data', (d) => { \n data = data + d.toString('utf8');\n }); \n res.on('end', () => { \n success({ body: JSON.parse(data), res });\n }); \n res.on('error', (e) => { \n failure(e);\n }); \n }); \n req.end();\n })\n}\n\nconst options = { \n key: backendKey, \n cert: backendCert, \n ca: backendCa, \n // we want mtls behavior\n requestCert: true, \n rejectUnauthorized: true\n}; \nhttps.createServer(options, (req, res) => { \n res.writeHead(200, {'Content-Type': 'application/json'});\n callApi2().then(resp => {\n res.write(JSON.stringify{ (\"message\": `Hello to ${req.socket.getPeerCertificate().subject.CN}`, api2: resp.body })); \n });\n}).listen(433);\n```\n\nthen, the descriptors will be :\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-app-deployment\nspec:\n selector:\n matchLabels:\n run: http-app-deployment\n replicas: 1\n template:\n metadata:\n labels:\n run: http-app-deployment\n spec:\n containers:\n - image: foo/http-app\n imagePullPolicy: IfNotPresent\n name: otoroshi\n ports:\n - containerPort: 443\n name: \"https\"\n volumeMounts:\n - name: apikey-volume\n # here you will be able to read apikey from files \n # - /var/run/secrets/kubernetes.io/apikeys/clientId\n # - /var/run/secrets/kubernetes.io/apikeys/clientSecret\n mountPath: \"/var/run/secrets/kubernetes.io/apikeys\"\n readOnly: true\n volumeMounts:\n - name: backend-cert-volume\n # here you will be able to read app cert from files \n # - /var/run/secrets/kubernetes.io/certs/backend/tls.crt\n # - /var/run/secrets/kubernetes.io/certs/backend/tls.key\n mountPath: \"/var/run/secrets/kubernetes.io/certs/backend\"\n readOnly: true\n - name: client-cert-volume\n # here you will be able to read app cert from files \n # - /var/run/secrets/kubernetes.io/certs/client/tls.crt\n # - /var/run/secrets/kubernetes.io/certs/client/tls.key\n mountPath: \"/var/run/secrets/kubernetes.io/certs/client\"\n readOnly: true\n volumes:\n - name: apikey-volume\n secret:\n # here we reference the secret name from apikey http-app-2-apikey-1\n secretName: secret-2\n - name: backend-cert-volume\n secret:\n # here we reference the secret name from cert http-app-certificate-backend\n secretName: http-app-certificate-backend-secret\n - name: client-cert-volume\n secret:\n # here we reference the secret name from cert http-app-certificate-client\n secretName: http-app-certificate-client-secret\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: http-app-service\nspec:\n ports:\n - port: 8443\n targetPort: https\n name: https\n selector:\n run: http-app-deployment\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ServiceGroup\nmetadata:\n name: http-app-group\n annotations:\n otoroshi.io/id: http-app-group\nspec:\n description: a group to hold services about the http-app\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-apikey-1\n# this apikey can be used to access the app\nspec:\n # a secret name secret-1 will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: secret-1\n authorizedEntities: \n - group_http-app-group\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-2-apikey-1\n# this apikey can be used to access another app in a different group\nspec:\n # a secret name secret-1 will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: secret-2\n authorizedEntities: \n - group_http-app-2-group\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-frontend\nspec:\n description: certificate for the http-app on otorshi frontend\n autoRenew: true\n csr:\n issuer: CN=Otoroshi Root\n hosts: \n - httpapp.foo.bar\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-front, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-backend\nspec:\n description: certificate for the http-app deployed on pods\n autoRenew: true\n # a secret name http-app-certificate-backend-secret will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: http-app-certificate-backend-secret\n csr:\n issuer: CN=Otoroshi Root\n hosts: \n - http-app-service \n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-back, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-client\nspec:\n description: certificate for the http-app\n autoRenew: true\n secretName: http-app-certificate-client-secret\n csr:\n issuer: CN=Otoroshi Root\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-client, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ServiceDescriptor\nmetadata:\n name: http-app-service-descriptor\nspec:\n description: the service descriptor for the http app\n groups: \n - http-app-group\n forceHttps: true\n hosts:\n - httpapp.foo.bar # hostname exposed oustide of the kubernetes cluster\n # - http-app-service-descriptor.global.otoroshi.mesh # implicit internal name inside the kubernetes cluster \n matchingRoot: /\n targets:\n - url: https://http-app-service:8443\n # alternatively, you can use serviceName and servicePort to use pods ip addresses\n # serviceName: http-app-service\n # servicePort: https\n mtlsConfig:\n # use mtls to contact the backend\n mtls: true\n certs: \n # reference the DN for the client cert\n - UID=httpapp-client, O=OtoroshiApps\n trustedCerts: \n # reference the DN for the CA cert \n - CN=Otoroshi Root\n sendOtoroshiHeadersBack: true\n xForwardedHeaders: true\n overrideHost: true\n allowHttp10: false\n publicPatterns:\n - /health\n additionalHeaders:\n x-foo: bar\n# here you can specify everything supported by otoroshi like jwt-verifiers, auth config, etc ... for more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html\n```\n\nnow with this descriptor deployed, you can access your app with a command like \n\n```sh\nCLIENT_ID=`kubectl get secret secret-1 -o jsonpath=\"{.data.clientId}\" | base64 --decode`\nCLIENT_SECRET=`kubectl get secret secret-1 -o jsonpath=\"{.data.clientSecret}\" | base64 --decode`\ncurl -X GET https://httpapp.foo.bar/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n## Expose Otoroshi to outside world\n\nIf you deploy Otoroshi on a kubernetes cluster, the Otoroshi service is deployed as a loadbalancer (service type: `LoadBalancer`). You'll need to declare in your DNS settings any name that can be routed by otoroshi going to the loadbalancer endpoint (CNAME or ip addresses) of your kubernetes distribution. If you use a managed kubernetes cluster from a cloud provider, it will work seamlessly as they will provide external loadbalancers out of the box. However, if you use a bare metal kubernetes cluster, id doesn't come with support for external loadbalancers (service of type `LoadBalancer`). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like [MetalLB](https://metallb.universe.tf/) that provide software `LoadBalancer` services to bare metal clusters or you can use and customize examples in the installation section.\n\n@@@ warning\nWe don't recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.\n@@@ \n\n## Access a service from inside the k8s cluster\n\n### Using host header overriding\n\nYou can access any service referenced in otoroshi, through otoroshi from inside the kubernetes cluster by using the otoroshi service name (if you use a template based on https://github.com/MAIF/otoroshi/tree/master/kubernetes/base deployed in the otoroshi namespace) and the host header with the service domain like :\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET -H 'Host: httpapp.foo.bar' https://otoroshi-service.otoroshi.svc.cluster.local:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using dedicated services\n\nit's also possible to define services that targets otoroshi deployment (or otoroshi workers deployment) and use then as valid hosts in otoroshi services \n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: my-awesome-service\nspec:\n selector:\n # run: otoroshi-deployment\n # or in cluster mode\n run: otoroshi-worker-deployment\n ports:\n - port: 8080\n name: \"http\"\n targetPort: \"http\"\n - port: 8443\n name: \"https\"\n targetPort: \"https\"\n```\n\nand access it like\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET https://my-awesome-service.my-namspace.svc.cluster.local:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using coredns integration\n\nYou can also enable the coredns integration to simplify the flow. You can use the the following keys in the plugin config :\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"coreDnsIntegration\": true, // enable coredns integration for intra cluster calls\n \"kubeSystemNamespace\": \"kube-system\", // the namespace where coredns is deployed\n \"corednsConfigMap\": \"coredns\", // the name of the coredns configmap\n \"otoroshiServiceName\": \"otoroshi-service\", // the name of the otoroshi service, could be otoroshi-workers-service\n \"otoroshiNamespace\": \"otoroshi\", // the namespace where otoroshi is deployed\n \"clusterDomain\": \"cluster.local\", // the domain for cluster services\n ...\n }\n}\n```\n\notoroshi will patch coredns config at startup then you can call your services like\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\nBy default, all services created from CRDs service descriptors are exposed as `${service-name}.${service-namespace}.otoroshi.mesh` or `${service-name}.${service-namespace}.svc.otoroshi.local`\n\n### Using coredns with manual patching\n\nyou can also patch the coredns config manually\n\n```sh\nkubectl edit configmaps coredns -n kube-system # or your own custom config map\n```\n\nand change the `Corefile` data to add the following snippet in at the end of the file\n\n```yaml\notoroshi.mesh:53 {\n errors\n health\n ready\n kubernetes cluster.local in-addr.arpa ip6.arpa {\n pods insecure\n upstream\n fallthrough in-addr.arpa ip6.arpa\n }\n rewrite name regex (.*)\\.otoroshi\\.mesh otoroshi-worker-service.otoroshi.svc.cluster.local\n forward . /etc/resolv.conf\n cache 30\n loop\n reload\n loadbalance\n}\n```\n\nyou can also define simpler rewrite if it suits you use case better\n\n```\nrewrite name my-service.otoroshi.mesh otoroshi-worker-service.otoroshi.svc.cluster.local\n```\n\ndo not hesitate to change `otoroshi-worker-service.otoroshi` according to your own setup. If otoroshi is not in cluster mode, change it to `otoroshi-service.otoroshi`. If otoroshi is not deployed in the `otoroshi` namespace, change it to `otoroshi-service.the-namespace`, etc.\n\nBy default, all services created from CRDs service descriptors are exposed as `${service-name}.${service-namespace}.otoroshi.mesh`\n\nthen you can call your service like \n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\n\ncurl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using old kube-dns system\n\nif your stuck with an old version of kubernetes, it uses kube-dns that is not supported by otoroshi, so you will have to provide your own coredns deployment and declare it as a stubDomain in the old kube-dns system. \n\nHere is an example of coredns deployment with otoroshi domain config\n\ncoredns.yaml\n: @@snip [coredns.yaml](../snippets/kubernetes/kustomize/base/coredns.yaml)\n\nthen you can enable the kube-dns integration in the otoroshi kubernetes job\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"kubeDnsOperatorIntegration\": true, // enable kube-dns integration for intra cluster calls\n \"kubeDnsOperatorCoreDnsNamespace\": \"otoroshi\", // namespace where coredns is installed\n \"kubeDnsOperatorCoreDnsName\": \"otoroshi-dns\", // name of the coredns service\n \"kubeDnsOperatorCoreDnsPort\": 5353, // port of the coredns service\n ...\n }\n}\n```\n\n### Using Openshift DNS operator\n\nOpenshift DNS operator does not allow to customize DNS configuration a lot, so you will have to provide your own coredns deployment and declare it as a stub in the Openshift DNS operator. \n\nHere is an example of coredns deployment with otoroshi domain config\n\ncoredns.yaml\n: @@snip [coredns.yaml](../snippets/kubernetes/kustomize/base/coredns.yaml)\n\nthen you can enable the Openshift DNS operator integration in the otoroshi kubernetes job\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"openshiftDnsOperatorIntegration\": true, // enable openshift dns operator integration for intra cluster calls\n \"openshiftDnsOperatorCoreDnsNamespace\": \"otoroshi\", // namespace where coredns is installed\n \"openshiftDnsOperatorCoreDnsName\": \"otoroshi-dns\", // name of the coredns service\n \"openshiftDnsOperatorCoreDnsPort\": 5353, // port of the coredns service\n ...\n }\n}\n```\n\ndon't forget to update the otoroshi `ClusterRole`\n\n```yaml\n- apiGroups:\n - operator.openshift.io\n resources:\n - dnses\n verbs:\n - get\n - list\n - watch\n - update\n```\n\n## CRD validation in kubectl\n\nIn order to get CRD validation before manifest deployments right inside kubectl, you can deploy a validation webhook that will do the trick. Also check that you have `otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator` request sink enabled.\n\nvalidation-webhook.yaml\n: @@snip [validation-webhook.yaml](../snippets/kubernetes/kustomize/base/validation-webhook.yaml)\n\n## Easier integration with otoroshi-sidecar\n\nOtoroshi can help you to easily use existing services without modifications while gettings all the perks of otoroshi like apikeys, mTLS, exchange protocol, etc. To do so, otoroshi will inject a sidecar container in the pod of your deployment that will handle call coming from otoroshi and going to otoroshi. To enable otoroshi-sidecar, you need to deploy the following admission webhook. Also check that you have `otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector` request sink enabled.\n\nsidecar-webhook.yaml\n: @@snip [sidecar-webhook.yaml](../snippets/kubernetes/kustomize/base/sidecar-webhook.yaml)\n\nthen it's quite easy to add the sidecar, just add the following label to your pod `otoroshi.io/sidecar: inject` and some annotations to tell otoroshi what certificates and apikeys to use.\n\n```yaml\nannotations:\n otoroshi.io/sidecar-apikey: backend-apikey\n otoroshi.io/sidecar-backend-cert: backend-cert\n otoroshi.io/sidecar-client-cert: oto-client-cert\n otoroshi.io/token-secret: secret\n otoroshi.io/expected-dn: UID=oto-client-cert, O=OtoroshiApps\n```\n\nnow you can just call you otoroshi handled apis from inside your pod like `curl http://my-service.namespace.otoroshi.mesh/api` without passing any apikey or client certificate and the sidecar will handle everything for you. Same thing for call from otoroshi to your pod, everything will be done in mTLS fashion with apikeys and otoroshi exchange protocol\n\nhere is a full example\n\nsidecar.yaml\n: @@snip [sidecar.yaml](../snippets/kubernetes/kustomize/base/sidecar.yaml)\n\n@@@ warning\nPlease avoid to use port `80` for your pod as it's the default port to access otoroshi from your pod and the call will be redirect to the sidecar via an iptables rule\n@@@\n\n## Daikoku integration\n\nIt is possible to easily integrate daikoku generated apikeys without any human interaction with the actual apikey secret. To do that, create a plan in Daikoku and setup the integration mode to `Automatic`\n\n@@@ div { .centered-img }\n\n@@@\n\nthen when a user subscribe for an apikey, he will only see an integration token\n\n@@@ div { .centered-img }\n\n@@@\n\nthen just create an ApiKey manifest with this token and your good to go \n\n```yaml\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-2-apikey-3\nspec:\n exportSecret: true \n secretName: secret-3\n daikokuToken: RShQrvINByiuieiaCBwIZfGFgdPu7tIJEN5gdV8N8YeH4RI9ErPYJzkuFyAkZ2xy\n```\n\n" - }, - { - "name": "scaling.md", - "id": "/deploy/scaling.md", - "url": "/deploy/scaling.html", - "title": "Scaling Otoroshi", - "content": "# Scaling Otoroshi\n\n## Using multiple instances with a front load balancer\n\nOtoroshi has been designed to work with multiple instances. If you already have an infrastructure using frontal load balancing, you just have to declare Otoroshi instances as the target of all domain names handled by Otoroshi\n\n## Using master / workers mode of Otoroshi\n\nYou can read everything about it in @ref:[the clustering section](../deploy/clustering.md) of the documentation.\n\n## Using IPVS\n\nYou can use [IPVS](https://en.wikipedia.org/wiki/IP_Virtual_Server) to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi. You can find example of configuration [here](http://www.linuxvirtualserver.org/VS-DRouting.html) \n\n## Using DNS Round Robin\n\nYou can use [DNS round robin technique](https://en.wikipedia.org/wiki/Round-robin_DNS) to declare multiple A records under the domain names handled by Otoroshi.\n\n## Using software L4/L7 load balancers\n\nYou can use software L4 load balancers like NGINX or HAProxy to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi.\n\nNGINX L7\n: @@snip [nginx-http.conf](../snippets/nginx-http.conf) \n\nNGINX L4\n: @@snip [nginx-tcp.conf](../snippets/nginx-tcp.conf) \n\nHA Proxy L7\n: @@snip [haproxy-http.conf](../snippets/haproxy-http.conf) \n\nHA Proxy L4\n: @@snip [haproxy-tcp.conf](../snippets/haproxy-tcp.conf) \n\n## Using a custom TCP load balancer\n\nYou can also use any other TCP load balancer, from a hardware box to a small js file like\n\ntcp-proxy.js\n: @@snip [tcp-proxy.js](../snippets/tcp-proxy.js) \n\ntcp-proxy.rs\n: @@snip [tcp-proxy.rs](../snippets/proxy.rs) \n\n" - }, - { - "name": "dev.md", - "id": "/dev.md", - "url": "/dev.html", - "title": "Developing Otoroshi", - "content": "# Developing Otoroshi\n\nIf you want to play with Otoroshis code, here are some tips\n\n## The tools\n\nYou will need\n\n* git\n* JDK 11\n* SBT 1.3.x\n* Node 13 + yarn 1.x\n\n## Clone the repository\n\n```sh\ngit clone https://github.com/MAIF/otoroshi.git\n```\n\nor fork otoroshi and clone your own repository.\n\n## Run otoroshi in dev mode\n\nto run otoroshi in dev mode, you'll need to run two separate process to serve the javascript UI and the server part.\n\n### Javascript side\n\njust go to `/otoroshi/javascript` and install the dependencies with\n\n```sh\nyarn install\n# or\nnpm install\n```\n\nthen run the dev server with\n\n```sh\nyarn start\n# or\nnpm run start\n```\n\n### Server side\n\nsetup SBT opts with\n\n```sh\nexport SBT_OPTS=\"-Xmx2G -Xss6M\"\n```\n\nthen just go to `/otoroshi` and run the sbt console with \n\n```sh\nsbt\n```\n\nthen in the sbt console run the following command\n\n```sh\n~run -Dotoroshi.storage=file -Dotoroshi.liveJs=true -Dhttps.port=9998 -Dotoroshi.privateapps.port=9999 -Dotoroshi.adminPassword=password -Dotoroshi.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dotoroshi.events.maxSize=0\n```\n\nor you can use the [sbt-revolver](https://github.com/spray/sbt-revolver) to run otoroshi locally for a more `prod` alike behavior (on the TLS part for instance)\n\n```sh\n~reStart\n# to pass jvm args, you can use: ~reStart --- -Dotoroshi.storage=memory ...\n```\n\nyou can now access your otoroshi instance at `http://otoroshi.oto.tools:9999`\n\n## Test otoroshi\n\nto run otoroshi test just go to `/otoroshi` and run the main test suite with\n\n```sh\nsbt 'testOnly OtoroshiTests'\n```\n\n## Create a release\n\njust go to `/otoroshi/javascript` and then build the UI\n\n```sh\nyarn install\nyarn build\n```\n\nthen go to `/otoroshi` and build the otoroshi distribution\n\n```sh\nsbt ';clean;compile;dist;assembly'\n```\n\nthe otoroshi build is waiting for you in `/otoroshi/target/scala-2.12/otoroshi.jar` or `/otoroshi/target/universal/otoroshi-1.x.x.zip`\n\n## Build the documentation\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/doc.sh all\n```\n\nThe documentation is located at `manual/target/paradox/site/main/`\n\n## Format the sources\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/fmt.sh\n```" - }, - { - "name": "apikeys.md", - "id": "/entities/apikeys.md", - "url": "/entities/apikeys.html", - "title": "Apikeys", - "content": "# Apikeys\n\nAn API key is linked to one or more service group and service descriptor to allow you to access any service descriptor linked or contained in one of the linked service group. You can, of course, create multiple API key for given service groups/service descriptors.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can found a concrete example @ref:[here](../how-to-s/secure-with-apikey.md)\n\n* `ApiKey Id`: the id is a unique random key that will represent this API key\n* `ApiKey Secret`: the secret is a random key used to validate the API key\n* `ApiKey Name`: a name for the API key, used for debug purposes\n* `ApiKey description`: a useful description for this apikey\n* `Valid until`: auto disable apikey after this date\n* `Enabled`: if the API key is disabled, then any call using this API key will fail\n* `Read only`: if the API key is in read only mode, every request done with this api key will only work for GET, HEAD, OPTIONS verbs\n* `Allow pass by clientid only`: here you allow client to only pass client id in a specific header in order to grant access to the underlying api\n* `Constrained services only`: this apikey can only be used on services using apikey routing constraints\n* `Authorized on`: the groups/services linked to this api key\n\n### Metadata and tags\n\n* `Tags`: tags attached to the api key\n* `Metadata`: metadata attached to the api key\n\n### Automatic secret rotation\n\nAPI can handle automatic secret rotation by themselves. When enabled, the rotation changes the secret every `Rotation every` duration. During the `Grace period` both secret will be usable.\n \n* `Enabled`: enabled automatic apikey secret rotation\n* `Rotation every`: rotate secrets every\n* `Grace period`: period when both secrets can be used\n* `Next client secret`: display the next generated client secret\n\n### Restrictions\n\n* `Enabled`: enable restrictions\n* `Allow last`: Otoroshi will test forbidden and notFound paths before testing allowed paths\n* `Allowed`: allowed paths\n* `Forbidden`: forbidden paths\n* `Not Found`: not found paths\n\n### Call examples\n\n* `Curl Command`: simple request with the api key passed by header\n* `Basic Auth. Header`: authorization Header with the api key as base64 encoded format\n* `Curl Command with Basic Auth. Header`: simple request with api key passed in the Authorization header as base64 format\n\n### Quotas\n\n* `Throttling quota`: the authorized number of calls per second\n* `Daily quota`: the authorized number of calls per day\n* `Monthly quota`: the authorized number of calls per month\n\n@@@ warning\n\nDaily and monthly quotas are based on the following rules :\n\n* daily quota is computed between 00h00:00.000 and 23h59:59.999 of the current day\n* monthly qutoas is computed between the first day of the month at 00h00:00.000 and the last day of the month at 23h59:59.999\n@@@\n\n### Quotas consumption\n\n* `Consumed daily calls`: the number of calls consumed today\n* `Remaining daily calls`: the remaining number of calls for today\n* `Consumed monthly calls`: the number of calls consumed this month\n* `Remaining monthly calls`: the remaining number of calls for this month\n\n" - }, - { - "name": "auth-modules.md", - "id": "/entities/auth-modules.md", - "url": "/entities/auth-modules.html", - "title": "Authentication modules", - "content": "# Authentication modules\n\nThe authentication modules are the resources to manage the the access to Otoroshi UI and to protect a service.\n\nAn authentication module can be as well use on guard to access to the Otoroshi UI as to protect an app.\n\nA `private app` is an Otoroshi service with an authentication module.\n\nThe list of supported authentication are :\n\n* `OAuth 2.0/2.1` : an authorization standard that allows a user to grant limited access to their resources on one site to another site, without having to expose their credentials\n* `OAuth 1.0a` : the original standard for access delegation\n* `In memory` : create users directly in Otoroshi with rights and metadata\n* `LDAP : Lightweight Directory Access Protocol` : connect users using a set of LDAP servers\n* `SAML V2 - Security Assertion Markup Language` : an open-standard, XML-based data format that allows businesses to communicate user authentication and authorization information to partner companies and enterprise applications their employees may use.\n\nAll authentication modules have a unique `id`, a `name` and a `description`.\n\nEach module has also the following fields : \n\n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n* `HttpOnly`: if enabled, the cookie cannot be accessed through client side script, prevent cross-site scripting (XSS) by not revealing the cookie to a third party\n* `Secure`: if enabled, avoid to include cookie in an HTTP Request without secure channel, typically HTTPs.\n* `Session max. age`: duration until the session expired\n* `User validators`: a list of validator that will check if a user that successfully logged in has the right to actually pass otoroshi based on the content of it's profile. A validator is composed of a [JSONPath](https://goessner.net/articles/JsonPath/) that will tell what to check and a value that is the expected value. The JSONPath will be applied on a document that will look like\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"randomId\": \"xxxxx\",\n \"name\": \"john.doe@otoroshi.io\",\n \"email\": \"john.doe@otoroshi.io\",\n \"authConfigId\": \"xxxxxxxx\",\n \"profile\": { // the profile shape depends heavily on the identity provider\n \"sub\": \"xxxxxx\",\n \"nickname\": \"john.doe\",\n \"name\": \"john.doe@otoroshi.io\",\n \"picture\": \"https://foo.bar/avatar.png\",\n \"updated_at\": \"2022-04-20T12:57:39.723Z\",\n \"email\": \"john.doe@otoroshi.io\",\n \"email_verified\": true,\n \"rights\": [\"one\", \"two\"]\n },\n \"token\": { // the token shape depends heavily on the identity provider\n \"access_token\": \"xxxxxx\",\n \"refresh_token\": \"yyyyyy\",\n \"id_token\": \"zzzzzz\",\n \"scope\": \"openid profile email address phone offline_access\",\n \"expires_in\": 86400,\n \"token_type\": \"Bearer\"\n },\n \"realm\": \"global-oauth-xxxxxxx\",\n \"otoroshiData\": {\n ...\n },\n \"createdAt\": 1650459462650,\n \"expiredAt\": 1650545862652,\n \"lastRefresh\": 1650459462650,\n \"metadata\": {},\n \"tags\": []\n}\n```\n\nthe expected value support some syntax tricks like \n\n* `Not(value)` on a string to check if the current value does not equals another value\n* `Regex(regex)` on a string to check if the current value matches the regex\n* `RegexNot(regex)` on a string to check if the current value does not matches the regex\n* `Wildcard(*value*)` on a string to check if the current value matches the value with wildcards\n* `WildcardNot(*value*)` on a string to check if the current value does not matches the value with wildcards\n* `Contains(value)` on a string to check if the current value contains a value\n* `ContainsNot(value)` on a string to check if the current value does not contains a value\n* `Contains(Regex(regex))` on an array to check if one of the item of the array matches the regex\n* `ContainsNot(Regex(regex))` on an array to check if one of the item of the array does not matches the regex\n* `Contains(Wildcard(*value*))` on an array to check if one of the item of the array matches the wildcard value\n* `ContainsNot(Wildcard(*value*))` on an array to check if one of the item of the array does not matches the wildcard value\n* `Contains(value)` on an array to check if the array contains a value\n* `ContainsNot(value)` on an array to check if the array does not contains a value\n\nfor instance to check if the current user has the right `two`, you can write the following validator\n\n```js\n{\n \"path\": \"$.profile.rights\",\n \"value\": \"Contains(two)\"\n}\n```\n\n## OAuth 2.0 / OIDC provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check these tutorials : @ref[Secure an app with keycloak](../how-to-s/secure-app-with-keycloak.md) or @ref[Secure an app with auth0](../how-to-s/secure-app-with-auth0.md)\n\n* `Use cookie`: If your OAuth2 provider does not support query param in redirect uri, you can use cookies instead\n* `Use json payloads`: the access token, sended to retrieve the user info, will be pass in body as JSON. If disabled, it will sended as Map.\n* `Enabled PKCE flow`: This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.\n* `Disable wildcard on redirect URIs`: As of OAuth 2.1, query parameters on redirect URIs are no longer allowed\n* `Refresh tokens`: Automatically refresh access token using the refresh token if available\n* `Read profile from token`: if enabled, the user profile will be read from the access token, otherwise the user profile will be retrieved from the user information url\n* `Super admins only`: All logged in users will have super admins rights\n* `Client ID`: a public identifier of your app\n* `Client Secret`: a secret known only to the application and the authorization server\n* `Authorize URL`: used to interact with the resource owner and get the authorization to access the protected resource\n* `Token URL`: used by the application in order to get an access token or a refresh token\n* `Introspection URL`: used to validate access tokens\n* `Userinfo URL`: used to retrieve the profile of the user\n* `Login URL`: used to redirect user to the login provider page\n* `Logout URL`: redirect uri used by the identity provider to redirect user after logging out\n* `Callback URL`: redirect uri sended to the identity provider to redirect user after successfully connecting\n* `Access token field name`: field used to search access token in the response body of the token URL call\n* `Scope`: presented scopes to the user in the consent screen. Scopes are space-separated lists of identifiers used to specify what access privileges are being requested\n* `Claims`: asked name/values pairs that contains information about a user.\n* `Name field name`: Retrieve name from token field\n* `Email field name`: Retrieve email from token field\n* `Otoroshi metadata field name`: Retrieve metadata from token field\n* `Otoroshi rights field name`: Retrieve user rights from user profile\n* `Extra metadata`: merged with the user metadata\n* `Data override`: merged with extra metadata when a user connects to a `private app`\n* `Rights override`: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.\n* `Api key metadata field name`: used to extract api key metadata from the OIDC access token \n* `Api key tags field name`: used to extract api key tags from the OIDC access token \n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n* `OIDC config url`: URI of the openid-configuration used to discovery documents. By convention, this URI ends with `.well-known/openid-configuration`\n* `Token verification`: What kind of algorithm you want to use to verify/sign your JWT token with\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: The Hmac secret\n* `Base64 encoded secret`: Is the secret encoded with base64\n* `Custom TLS Settings`: TLS settings for JWKS fetching\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `Trust all`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with JWKS server\n* `Trusted certificates`: list of trusted certificates received from JWKS server\n\n## OAuth 1.0a provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : @ref[Secure an app with OAuth 1.0a](../how-to-s/secure-with-oauth1-client.md)\n\n* `Http Method`: method used to get request token and the access token \n* `Consumer key`: the identifier portion of the client credentials (equivalent to a username)\n* `Consumer secret`: the identifier portion of the client credentials (equivalent to a password)\n* `Request Token URL`: url to retrieve the request token\n* `Authorize URL`: used to redirect user to the login page\n* `Access token URL`: used to retrieve the access token from the server\n* `Profile URL`: used to get the user profile\n* `Callback URL`: used to redirect user when successfully connecting\n* `Rights override`: override the rights of the connected user. With JSON format, each authenticated user, using email, can be associated to a list of rights on tenants and Otoroshi teams.\n\n## LDAP Authentication provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : @ref[Secure an app with LDAP](../how-to-s/secure-app-with-ldap.md)\n\n* `Basic auth.`: if enabled, user and password will be extract from the `Authorization` header as a Basic authentication. It will skipped the login Otoroshi page \n* `Allow empty password`: LDAP servers configured by default with the possibility to connect without password can be secured by this module to ensure that user provides a password\n* `Super admins only`: All logged in users will have super admins rights\n* `Extract profile`: extract LDAP profile in the Otoroshi user\n* `LDAP Server URL`: list of LDAP servers to join. Otoroshi use this list in sequence and swap to the next server, each time a server breaks in timeout\n* `Search Base`: used to global filter\n* `Users search base`: concat with search base to search users in LDAP\n* `Mapping group filter`: map LDAP groups with Otoroshi rights\n* `Search Filter`: used to filter users. *\\${username}* is replace by the email of the user and compare to the given field\n* `Admin username (bind DN)`: holds the name of the environment property for specifying the identity of the principal for authenticating the caller to the service\n* `Admin password`: holds the name of the environment property for specifying the credentials of the principal for authenticating the caller to the service\n* `Extract profile filters attributes in`: keep only attributes which are matching the regex\n* `Extract profile filters attributes not in`: keep only attributes which are not matching the regex\n* `Name field name`: Retrieve name from LDAP field\n* `Email field name`: Retrieve email from LDAP field\n* `Otoroshi metadata field name`: Retrieve metadata from LDAP field\n* `Extra metadata`: merged with the user metadata\n* `Data override`: merged with extra metadata when a user connects to a `private app`\n* `Additional rights group`: list of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.\n* `Rights override`: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.\n\n## In memory provider\n\n* `Basic auth.`: if enabled, user and password will be extract from the `Authorization` header as a Basic authentication. It will skipped the login Otoroshi page \n* `Login with WebAuthn` : enabled logging by WebAuthn\n* `Users`: list of users with *name*, *email* and *metadata*. The default password is *password*. The edit button is useful when you want to change the password of the user. The reset button reinitialize the password. \n* `Users raw`: show the registered users with their profile and their rights. You can edit directly each field, especially the rights of the user.\n\n## SAML v2 provider\n\n* `Single sign on URL`: the Identity Provider Single Sign-On URL\n* `The protocol binding for the login request`: the protocol binding for the login request\n* `Single Logout URL`: a SAML flow that allows the end-user to logout from a single session and be automatically logged out of all related sessions that were established during SSO\n* `The protocol binding for the logout request`: the protocol binding for the logout request\n* `Sign documents`: Should SAML Request be signed by Otoroshi ?\n* `Validate Assertions Signature`: Enable/disable signature validation of SAML assertions\n* `Validate assertions with Otoroshi certificate`: validate assertions with Otoroshi certificate. If disabled, the `Encryption Certificate` and `Encryption Private Key` fields can be used to pass a certificate and a private key to validate assertions.\n* `Encryption Certificate`: certificate used to verify assertions\n* `Encryption Private Key`: privaye key used to verify assertions\n* `Signing Certificate`: certicate used to sign documents\n* `Signing Private Key`: private key to sign documents\n* `Signature al`: the signature algorithm to use to sign documents\n* `Canonicalization Method`: canonicalization method for XML signatures \n* `Encryption KeyPair`: the keypair used to sign/verify assertions\n* `Name ID Format`: SP and IdP usually communicate each other about a subject. That subject should be identified through a NAME-IDentifier, which should be in some format so that It is easy for the other party to identify it based on the Format\n* `Use NameID format as email`: use NameID format as email. If disabled, the email will be search from the attributes\n* `URL issuer`: provide the URL to the IdP's who will issue the security token\n* `Validate Signature`: enable/disable signature validation of SAML responses\n* `Validate Assertions Signature`: should SAML Assertions to be decrypted ?\n* `Validating Certificates`: the certificate in PEM format that must be used to check for signatures.\n\n## Special routes\n\nwhen using private apps with auth. modules, you can access special routes that can help you \n\n```sh \nGET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/logout' # trigger logout for the current auth. module\nGET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/me' # get the current logged user profile (do not forget to pass cookies)\n```\n\n## Related pages\n* @ref[Secure an app with auth0](../how-to-s/secure-app-with-auth0.md)\n* @ref[Secure an app with keycloak](../how-to-s/secure-app-with-keycloak.md)\n* @ref[Secure an app with LDAP](../how-to-s/secure-app-with-ldap.md)\n* @ref[Secure an app with OAuth 1.0a](../how-to-s/secure-with-oauth1-client.md)" - }, - { - "name": "certificates.md", - "id": "/entities/certificates.md", - "url": "/entities/certificates.html", - "title": "Certificates", - "content": "# Certificates\n\nAll generated and imported certificates are listed in the `https://otoroshi.xxxx/bo/dashboard/certificates` page. All those certificates can be used to serve traffic with TLS, perform mTLS calls, sign and verify JWT tokens.\n\nThe list of available actions are:\n\n* `Add item`: redirects the user on the certificate creation page. It's useful when you already had a certificate (like a pem file) and that you want to load it in Otoroshi.\n* `Let's Encrypt certificate`: asks a certificate matching a given host to Let's encrypt \n* `Create certificate`: issues a certificate with an existing Otoroshi certificate as CA.\n* `Import .p12 file`: loads a p12 file as certificate\n\n## Add item\n\n* `Id`: the generated unique id of the certificate\n* `Name`: the name of the certificate\n* `Description`: the description of the certificate\n* `Auto renew cert.`: certificate will be issued when it will be expired. Only works with a CA from Otoroshi and a known private key\n* `Client cert.`: the certificate generated will be used to identicate a client to a server\n* `Keypair`: the certificate entity will be a pair of public key and private key.\n* `Public key exposed`: if true, the public key will be exposed on `http://otoroshi-api.your-domain/.well-known/jwks.json`\n* `Certificate status`: the current status of the certificate. It can be valid if the certificate is not revoked and not expired, or equal to the reason of the revocation\n* `Certificate full chain`: list of certificates used to authenticate a client or a server\n* `Certificate private key`: the private key of the certificate or nothing if wanted. You can omit it if you want just add a certificte full chain to trust them.\n* `Private key password`: the password to protect the private key\n* `Certificate tags`: the tags attached to the certificate\n* `Certaificate metadata`: the metadata attached to the certificate\n\n## Let's Encrypt certificate\n\n* `Let's encrypt`: if enabled, the certificate will be generated by Let's Encrypt. If disabled, the user will be redirect to the `Create certificate` page\n* `Host`: the host send to Let's encrypt to issue the certificate\n\n## Create certificate view\n\n* `Issuer`: the CA used to sign your certificate\n* `CA certificate`: if enabled, the certificate will be used as an authority certificate. Once generated, it will be use as CA to sign the new certificates\n* `Let's Encrypt`: redirects to the Let's Encrypt page to request a certificate\n* `Client certificate`: the certificate generated will be used to identicate a client to a server\n* `Include A.I.A`: include authority information access urls in the certificate\n* `Key Type`: the type of the private key\n* `Key Size`: the size of the private key\n* `Signature Algorithm`: the signature algorithm used to sign the certificate\n* `Digest Algorithm`: the digest algorithm used\n* `Validity`: how much time your certificate will be valid\n* `Subject DN`: the subject DN of your certificate\n* `Hosts`: the hosts of your certificate\n\n" - }, - { - "name": "data-exporters.md", - "id": "/entities/data-exporters.md", - "url": "/entities/data-exporters.html", - "title": "Data exporters", - "content": "# Data exporters\n\nThe data exporters are the way to export alerts and events from Otoroshi to an external storage.\n\nTo try them, you can folllow @ref[this tutorial](../how-to-s/export-alerts-using-mailgun.md).\n\n## Common fields\n\n* `Type`: the type of event exporter\n* `Enabled`: enabled or not the exporter\n* `Name`: given name to the exporter\n* `Description`: the data exporter description\n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n\nAll exporters are split in three parts. The first and second parts are common and the last are specific by exporter.\n\n* `Filtering and projection` : section to filter the list of sent events and alerts. The projection field allows you to export only certain event fields and reduce the size of exported data. It's composed of `Filtering` and `Projection` fields. To get a full usage of this elements, read @ref:[this section](#matching-and-projections)\n* `Queue details`: set of fields to adjust the workers of the exporter. \n * `Buffer size`: if elements are pushed onto the queue faster than the source is consumed the overflow will be handled with a strategy specified by the user. Keep in memory the number of events.\n * `JSON conversion workers`: number of workers used to transform events to JSON format in paralell\n * `Send workers`: number of workers used to send transformed events\n * `Group size`: chunk up this stream into groups of elements received within a time window (the time window is the next field)\n * `Group duration`: waiting time before sending the group of events. If the group size is reached before the group duration, the events will be instantly sent\n \nFor the last part, the `Exporter configuration` will be detail individually.\n\n## Matching and projections\n\n**Filtering** is used to **include** or **exclude** some kind of events and alerts. For each include and exclude field, you can add a list of key-value. \n\nLet's say we only want to keep Otoroshi alerts\n```json\n{ \"include\": [{ \"@type\": \"AlertEvent\" }] }\n```\n\nOtoroshi provides a list of rules to keep only events with specific values. We will use the following event to illustrate.\n\n```json\n{\n \"foo\": \"bar\",\n \"type\": \"AlertEvent\",\n \"alert\": \"big-alert\",\n \"status\": 200,\n \"codes\": [\"a\", \"b\"],\n \"inner\": {\n \"foo\": \"bar\",\n \"bar\": \"foo\"\n }\n}\n```\n\nThe rules apply with the previous example as event.\n\n@@@div { #filtering }\n \n@@@\n\n\n\n**Projection** is a list of fields to export. In the case of an empty list, all the fields of an event will be exported. In other case, **only** the listed fields will be exported.\n\nLet's say we only want to keep Otoroshi alerts and only type, timestamp and id of each exported events\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nAn other possibility is to **rename** the exported field. This value will be the same but the exported field will have a different name.\n\nLet's say we want to rename all `@id` field with `unique-id` as key\n\n```json\n{ \"@id\": \"unique-id\" }\n```\n\nThe last possiblity is to retrieve a sub-object of an event. Let's say we want to get the name of each exported user of events.\n\n```json\n{ \"user\": { \"name\": true } }\n```\n\nYou can also expand the entire source object with \n\n```json\n{\n \"$spread\": true\n}\n```\n\nand the remove fields you don't want with \n\n```json\n{\n \"fieldthatidontwant\": false\n}\n```\n\n## Elastic\n\nWith this kind of exporter, every matching event will be sent to an elastic cluster (in batch). It is quite useful and can be used in combination with [elastic read in global config](./global-config.html#analytics-elastic-dashboard-datasource-read-)\n\n* `Cluster URI`: Elastic cluster URI\n* `Index`: Elastic index \n* `Type`: Event type (not needed for elasticsearch above 6.x)\n* `User`: Elastic User (optional)\n* `Password`: Elastic password (optional)\n* `Version`: Elastic version (optional, if none provided it will be fetched from cluster)\n* `Apply template`: Automatically apply index template\n* `Check Connection`: Button to test the configuration. It will displayed a modal with checked point, and if the case of it's successfull, it will displayed the found version of the Elasticsearch and the index used\n* `Manually apply index template`: try to put the elasticsearch template by calling the api of elasticsearch\n* `Show index template`: try to retrieve the current index template presents in elasticsearch\n* `Client side temporal indexes handling`: When enabled, Otoroshi will manage the creation of indexes. When it's disabled, Otoroshi will push in the same index\n* `One index per`: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch \n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n## Webhook \n\nWith this kind of exporter, every matching event will be sent to a URL (in batch) using a POST method and an JSON array body.\n\n* `Alerts hook URL`: url used to post events\n* `Hook Headers`: headers add to the post request\n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n\n## Pulsar \n\nWith this kind of exporter, every matching event will be sent to an [Apache Pulsar topic](https://pulsar.apache.org/)\n\n\n* `Pulsar URI`: URI of the pulsar server\n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n* `Pulsar tenant`: tenant on the pulsar server\n* `Pulsar namespace`: namespace on the pulsar server\n* `Pulsar topic`: topic on the pulsar server\n\n## Kafka \n\nWith this kind of exporter, every matching event will be sent to an [Apache Kafka topic](https://kafka.apache.org/)\n\n* `Kafka Servers`: the list of servers to contact to connect the Kafka client with the Kafka cluster\n* `Kafka keypass`: the keystore password if you use a keystore/truststore to connect to Kafka cluster\n* `Kafka keystore path`: the keystore path on the server if you use a keystore/truststore to connect to Kafka cluster\n* `Kafka truststore path`: the truststore path on the server if you use a keystore/truststore to connect to Kafka cluster\n* `Custom TLS Settings`: enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n* `Kafka topic`: the topic on which Otoroshi alerts will be sent\n\n## Mailer \n\nWith this kind of exporter, every matching event will be sent in batch as an email (using one of the following email provider)\n\nOtoroshi supports 5 exporters of email type.\n\n### Console\n\nNothing to add. The events will be write on the standard output.\n\n### Generic\n\n* `Mailer url`: URL used to push events\n* `Headers`: headers add to the push requests\n* `Email addresses`: recipients of the emails\n\n### Mailgun\n\n* `EU`: is EU server ? if enabled, *https://api.eu.mailgun.net/* will be used, otherwise, the US URL will be used : *https://api.mailgun.net/*\n* `Mailgun api key`: API key of the mailgun account\n* `Mailgun domain`: domain name of the mailgun account\n* `Email addresses`: recipients of the emails\n\n### Mailjet\n\n* `Public api key`: public key of the mailjet account\n* `Private api key`: private key of the mailjet account\n* `Email addresses`: recipients of the emails\n\n### Sendgrid\n\n* `Sendgrid api key`: api key of the sendgrid account\n* `Email addresses`: recipients of the emails\n\n## File \n\n* `File path`: path where the logs will be write \n* `Max file size`: when size is reached, Otoroshi will create a new file postfixed by the current timestamp\n\n## GoReplay file\n\nWith this kind of exporter, every matching event will be sent to a `.gor` file compatible with [GoReplay](https://goreplay.org/). \n\n@@@ warning\nthis exporter will only be able to catch `TrafficCaptureEvent`. Those events are created when a route (or the global config) of the @ref:[new proxy engine](../next/engine.md) is setup to capture traffic using the `capture` flag.\n@@@\n\n* `File path`: path where the logs will be write \n* `Max file size`: when size is reached, Otoroshi will create a new file postfixed by the current timestamp\n* `Capture requests`: capture http requests in the `.gor` file\n* `Capture responses`: capture http responses in the `.gor` file\n\n## Console \n\nNothing to add. The events will be write on the standard output.\n\n## Custom \n\nThis type of exporter let you the possibility to write your own exporter with your own rules. To create an exporter, we need to navigate to the plugins page, and to create a new item of type exporter.\n\nWhen it's done, the exporter will be visible in this list.\n\n* `Exporter config.`: the configuration of the custom exporter.\n\n## Metrics \n\nThis plugin is useful to rewrite the metric labels exposed on the `/metrics` endpoint.\n\n* `Labels`: list of metric labels. Each pair contains an existing field name and the new name." - }, - { - "name": "global-config.md", - "id": "/entities/global-config.md", - "url": "/entities/global-config.html", - "title": "Global config", - "content": "# Global config\n\nThe global config, named `Danger zone` in Otoroshi, is the place to configure Otoroshi globally. \n\n> Warning: In this page, the configuration is really sensitive and affect the global behaviour of Otoroshi.\n\n\n### Misc. Settings\n\n\n* `Maintenance mode` : It pass every single service in maintenance mode. If an user calls a service, the maintenance page will be displayed\n* `No OAuth login for BackOffice` : Forces admins to login only with user/password or user/password/u2F device\n* `API Read Only`: Freeze the Otoroshi datastore in read only mode. Only people with access to the actual underlying datastore will be able to disable this.\n* `Auto link default` : When no group is specified on a service, it will be assigned to default one\n* `Use circuit breakers` : Use circuit breaker on all services\n* `Use new http client as the default Http client` : All http calls will use the new http client by default\n* `Enable live metrics` : Enable live metrics in the Otoroshi cluster. Performs a lot of writes in the datastore\n* `Digitus medius` : Use middle finger emoji as a response character for endless HTTP responses.\n* `Limit conc. req.` : Limit the number of concurrent request processed by Otoroshi to a certain amount. Highly recommended for resilience\n* `Use X-Forwarded-* headers for routing` : When evaluating routing of a request, X-Forwarded-* headers will be used if presents\n* `Max conc. req.` : Maximum number of concurrent requests processed by otoroshi.\n* `Max HTTP/1.0 resp. size` : Maximum size of an HTTP/1.0 response in bytes. After this limit, response will be cut and sent as is. The best value here should satisfy (maxConcurrentRequests * maxHttp10ResponseSize) < process.memory for worst case scenario.\n* `Max local events` : Maximum number of events stored.\n* `Lines` : *deprecated* \n\n### IP address filtering settings\n\n* `IP allowed list`: Only IP addresses that will be able to access Otoroshi exposed services\n* `IP blocklist`: IP addresses that will be refused to access Otoroshi exposed services\n* `Endless HTTP Responses`: IP addresses for which each request will return around 128 Gb of 0s\n\n\n### Quotas settings\n\n* `Global throttling`: The max. number of requests allowed per second globally on Otoroshi\n* `Throttling per IP`: The max. number of requests allowed per second per IP address globally on Otoroshi\n\n### Analytics: Elastic dashboard datasource (read)\n\n* `Cluster URI`: Elastic cluster URI\n* `Index`: Elastic index \n* `Type`: Event type (not needed for elasticsearch above 6.x)\n* `User`: Elastic User (optional)\n* `Password`: Elastic password (optional)\n* `Version`: Elastic version (optional, if none provided it will be fetched from cluster)\n* `Apply template`: Automatically apply index template\n* `Check Connection`: Button to test the configuration. It will displayed a modal with checked point, and if the case of it's successfull, it will displayed the found version of the Elasticsearch and the index used\n* `Manually apply index template`: try to put the elasticsearch template by calling the api of elasticsearch\n* `Show index template`: try to retrieve the current index template presents in elasticsearch\n* `Client side temporal indexes handling`: When enabled, Otoroshi will manage the creation of indexes. When it's disabled, Otoroshi will push in the same index\n* `One index per`: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch \n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `TrustAll`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with elasticsearch\n* `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n\n### Statsd settings\n\n* `Datadog agent`: The StatsD agent is a Datadog agent\n* `StatsD agent host`: The host on which StatsD agent is listening\n* `StatsD agent port`: The port on which StatsD agent is listening (default is 8125)\n\n\n### Backoffice auth. settings\n\n* `Backoffice auth. config`: the authentication module used in front of Otoroshi. It will be used to connect to Otoroshi on the login page\n\n### Let's encrypt settings\n\n* `Enabled`: when enabled, Otoroshi will have the possiblity to sign certificate from let's encrypt notably in the SSL/TSL Certificates page \n* `Server URL`: ACME endpoint of let's encrypt \n* `Email addresses`: (optional) list of addresses used to order the certificates \n* `Contact URLs`: (optional) list of addresses used to order the certificates \n* `Public Key`: used to ask a certificate to let's encrypt, generated by Otoroshi \n* `Private Key`: used to ask a certificate to let's encrypt, generated by Otoroshi \n\n\n### CleverCloud settings\n\nOnce configured, you can register one clever cloud app of your organization directly as an Otoroshi service.\n\n* `CleverCloud consumer key`: consumer key of your clever cloud OAuth 1.0 app\n* `CleverCloud consumer secret`: consumer secret of your clever cloud OAuth 1.0 app\n* `OAuth Token`: oauth token of your clever cloud OAuth 1.0 app\n* `OAuth Secret`: oauth token secret of your clever cloud OAuth 1.0 app \n* `CleverCloud orga. Id`: id of your clever cloud organization\n\n### Global scripts\n\nGlobal scripts will be deprecated soon, please use global plugins instead (see the next section)!\n\n### Global plugins\n\n* `Enabled`: enabled all global plugins\n* `Plugins`: list of added plugins to your instance\n* `Plugin configuration`: each added plugin have a configuration that you can override from this field\n\n### Proxies\n\nIn this section, you can add a list of proxies for :\n\n* Proxy for alert emails (mailgun)\n* Proxy for alert webhooks\n* Proxy for Clever-Cloud API access\n* Proxy for services access\n* Proxy for auth. access (OAuth, OIDC)\n* Proxy for client validators\n* Proxy for JWKS access\n* Proxy for elastic access\n\nEach proxy has the following fields \n\n* `Proxy host`: host of proxy\n* `Proxy port`: port of proxy\n* `Proxy principal`: user of proxy\n* `Proxy password`: password of proxy\n* `Non proxy host`: IP address that can access the service\n\n### Quotas alerting settings\n\n* `Enable quotas exceeding alerts`: When apikey quotas is almost exceeded, an alert will be sent \n* `Daily quotas threshold`: The percentage of daily calls before sending alerts\n* `Monthly quotas threshold`: The percentage of monthly calls before sending alerts\n\n### User-Agent extraction settings\n\n* `User-Agent extraction`: Allow user-agent details extraction. Can have impact on consumed memory. \n\n### Geolocation extraction settings\n\nExtract an geolocation for each call to Otoroshi.\n\n### Tls Settings\n\n* `Use random cert.`: Use the first available cert none matches the current domain\n* `Default domain`: When the SNI domain cannot be found, this one will be used to find the matching certificate \n* `Trust JDK CAs (server)`: Trust JDK CAs. The CAs from the JDK CA bundle will be proposed in the certificate request when performing TLS handshake \n* `Trust JDK CAs (trust)`: Trust JDK CAs. The CAs from the JDK CA bundle will be used as trusted CAs when calling HTTPS resources \n* `Trusted CAs (server)`: Select the trusted CAs you want for TLS terminaison. Those CAs only will be proposed in the certificate request when performing TLS handshake \n\n\n### Auto Generate Certificates\n\n* `Enabled`: Generate certificates on the fly when they not exist\n* `Reply Nicely`: When not allowed domain name, accept connection and display a nice error message \n* `CA`: certificate CA used to generate missing certificate\n* `Allowed domains`: Allowed domains\n* `Not allowed domains`: Allowed domains\n \n\n### Global metadata\n\n* `Tags`: tags attached to the global config\n* `Metadata`: metadata attached to the global config\n\n### Actions at the bottom of the page\n\n* `Recover from a full export file`: Load global configuration from a previous export\n* `Full export`: Export with all created entities\n* `Full export (ndjson)`: Export your full state of database to ndjson format\n* `JSON`: Get the global config at JSON format \n* `YAML`: Get the global config at YAML format \n* `Enable Panic Mode`: Log out all users from UI and prevent any changes to the database by setting the admin Otoroshi api to read-only. The only way to exit of this mode is to disable this mode directly in the database. " - }, - { - "name": "index.md", - "id": "/entities/index.md", - "url": "/entities/index.html", - "title": "", - "content": "\n# Main entities\n\nIn this section, we will pass through all the main Otoroshi entities. Otoroshi entities are the main items stored in otoroshi datastore that will be used to configure routing, authentication, etc.\n\nAny entity has the following properties\n\n* `location` or `_loc`: the location of the entity (organization and team)\n* `id`: the id of the entity (except for apikeys)\n* `name`: the name of the entity\n* `description`: the description of the entity (optional)\n* `tags`: free tags that you can put on any entity to help you manage it, automate it, etc.\n* `metadata`: free key/value tuples that you can put on any entity to help you manage it, automate it, etc.\n\n@@@div { .plugin .entities }\n\n
\nOrganizations\nThis the most high level for grouping resources.\n
\n@ref:[View](./organizations.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nTeams\nOrganize your resources by teams\n
\n@ref:[View](./teams.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nService groups\nGroup your services\n
\n@ref:[View](./service-groups.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nJWT verifiers\nVerify and forge token by services.\n
\n@ref:[View](./jwt-verifiers.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nApikeys\nAdd security to your services using apikeys\n
\n@ref:[View](./apikeys.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nGlobal Config\nThe danger zone of Otoroshi\n
\n@ref:[View](./global-config.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nService descriptors\nProxy your applications with service descriptors\n
\n@ref:[View](./service-descriptors.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nTCP services\n\n
\n@ref:[View](./tcp-services.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nAuth. modules\nSecure the Otoroshi UI and your web apps\n
\n@ref:[View](./auth-modules.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nCertificates\nAdd secure communication between Otoroshi, clients and services\n
\n@ref:[View](./certificates.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nData exporters\nExport alerts, events ands logs\n
\n@ref:[View](./data-exporters.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nScripts\n\n
\n@ref:[View](./scripts.md)\n@@@\n\n@@@ index\n\n* [Organizations](./organizations.md)\n* [Teams](./teams.md)\n* [Global Config](./global-config.md)\n* [Apikeys](./apikeys.md)\n* [Service groups](./service-groups.md)\n* [Service descriptors](./service-descriptors.md)\n* [Auth. modules](./auth-modules.md)\n* [Certificates](./certificates.md)\n* [JWT verifiers](./jwt-verifiers.md)\n* [Data exporters](./data-exporters.md)\n* [Scripts](./scripts.md)\n* [TCP services](./tcp-services.md)\n\n@@@\n" - }, - { - "name": "jwt-verifiers.md", - "id": "/entities/jwt-verifiers.md", - "url": "/entities/jwt-verifiers.html", - "title": "JWT verifiers", - "content": "# JWT verifiers\n\nSometimes, it can be pretty useful to verify Jwt tokens coming from other provider on some services. Otoroshi provides a tool to do that per service.\n\n* `Name`: name of the JWT verifier\n* `Description`: a simple description\n* `Strict`: if not strict, request without JWT token will be allowed to pass. This option is helpful when you want to force the presence of tokens in each request on a specific service \n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n\nEach JWT verifier is configurable in three steps : the `location` where find the token in incoming requests, the `validation` step to check the signature and the presence of claims in tokens, and the last step, named `Strategy`.\n\n## Token location\n\nAn incoming token can be found in three places.\n\n#### In query string\n\n* `Source`: JWT token location in query string\n* `Query param name`: the name of the query param where JWT is located\n\n#### In a header\n\n* `Source`: JWT token location in a header\n* `Header name`: the name of the header where JWT is located\n* `Remove value`: when the token is read, this value will be remove of header value (example: if the header value is *Bearer xxxx*, the *remove value* could be Bearer  don't forget the space at the end of the string)\n\n#### In a cookie\n\n* `Source`: JWT token location in a cookie\n* `Cookie name`: the name of the cookie where JWT is located\n\n## Token validation\n\nThis section is used to verify the extracted token from specified location.\n\n* `Algo.`: What kind of algorithm you want to use to verify/sign your JWT token with\n\nAccording to the selected algorithm, the validation form will change.\n\n#### Hmac + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: used to verify the token\n* `Base64 encoded secret`: if enabled, the extracted token will be base64 decoded before it is verifier\n\n#### RSASSA-PKCS1 + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Public key`: the RSA public key\n* `Private key`: the RSA private key that can be empty if not used for JWT token signing\n\n#### ECDSA + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Public key`: the ECDSA public key\n* `Private key`: the ECDSA private key that can be empty if not used for JWT token signing\n\n#### RSASSA-PKCS1 + SHA from KeyPair\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `KeyPair`: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page\n \n#### ECDSA + SHA from KeyPair\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `KeyPair`: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page\n\n#### Otoroshi KeyPair from token kid (only for verification)\n* `Use only exposed keypairs`: if enabled, Otoroshi will only use the key pairs that are exposed on the well-known. If disabled, it will search on any registered key pairs.\n\n#### JWK Set (only for verification)\n\n* `URL`: the JWK set URL where the public keys are exposed\n* `HTTP call timeout`: timeout for fetching the keyset\n* `TTL`: cache TTL for the keyset\n* `HTTP Headers`: the HTTP headers passed\n* `Key type`: type of the key searched in the jwks\n\n*TLS settings for JWKS fetching*\n\n* `Custom TLS Settings`: TLS settings for JWKS fetching\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `Trust all`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with JWKS server\n* `Trusted certificates`: list of trusted certificates received from JWKS server\n\n*Proxy*\n\n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n\n## Strategy\n\nThe first step is to select the verifier strategy. Otoroshi supports 4 types of JWT verifiers:\n\n* `Default JWT token` will add a token if no present. \n* `Verify JWT token` will only verifiy token signing and fields values if provided. \n* `Verify and re-sign JWT token` will verify the token and will re-sign the JWT token with the provided algo. settings. \n* `Verify, re-sign and transform JWT token` will verify the token, re-sign and will be able to transform the token.\n\nAll verifiers has the following properties: \n\n* `Verify token fields`: when the JWT token is checked, each field specified here will be verified with the provided value\n* `Verify token array value`: when the JWT token is checked, each field specified here will be verified if the provided value is contained in the array\n\n\n#### Default JWT token\n\n* `Strict`: if token is already present, the call will fail\n* `Default value`: list of claims of the generated token. These fields support raw values or language expressions. See the documentation about @ref:[the expression language](../topics/expression-language.md)\n\n#### Verify JWT token\n\nNo specific values needed. This kind of verifier needs only the two fields `Verify token fields` and `Verify token array value`.\n\n#### Verify and re-sign JWT token\n\nWhen `Verify and re-sign JWT token` is chosen, the `Re-sign settings` appear. All fields of `Re-sign settings` are the same of the `Token validation` section. The only difference is that the values are used to sign the new token and not to validate the token.\n\n\n#### Verify, re-sign and transform JWT token\n\nWhen `Verify, re-sign and transform JWT token` is chosen, the `Re-sign settings` and `Transformation settings` appear.\n\nThe `Re-sign settings` are used to sign the new token and has the same fields than the `Token validation` section.\n\nFor the `Transformation settings` section, the fields are:\n\n* `Token location`: the location where to find/set the JWT token\n* `Header name`: the name of the header where JWT is located\n* `Prepend value`: remove a value inside the header value\n* `Rename token fields`: when the JWT token is transformed, it is possible to change a field name, just specify origin field name and target field name\n* `Set token fields`: when the JWT token is transformed, it is possible to add new field with static values, just specify field name and value\n* `Remove token fields`: when the JWT token is transformed, it is possible to remove fields" - }, - { - "name": "organizations.md", - "id": "/entities/organizations.md", - "url": "/entities/organizations.html", - "title": "Organizations", - "content": "# Organizations\n\nThe resources of Otoroshi are grouped by `Organization`. This the highest level for grouping resources.\n\nAn organization have a unique `id`, a `name` and a `description`. As all Otoroshi resources, an Organization have a list of tags and metadata associated.\n\nFor example, you can use the organizations as a mean of :\n\n* to seperate resources by services or entities in your enterprise\n* to split internal and external usage of the resources (it's useful when you have a list of services deployed in your company and another one deployed by your partners)\n\n@@@ div { .centered-img }\n\n@@@\n\n## Access to the list of organizations\n\nTo visualize and edit the list of organizations, you can navigate to your instance on the `https://otoroshi.xxxxxx/bo/dashboard/organizations` route or click on the cog icon and select the organizations button.\n\nOnce on the page, you can create a new item, edit an existing organization or delete an existing one.\n\n> When an organization is deleted, the resources associated are not deleted. On the other hand, the organization and the team of associated resources are let empty.\n\n## Entities location\n\nAny otoroshi entity has a location property (`_loc` when serialized to json) explaining where and by whom the entity can be seen. \n\nAn entity can be part of one organization (`tenant` in the json document)\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": ...\n }\n ...\n}\n```\n\nor all organizations\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"*\",\n \"teams\": ...\n }\n ...\n}\n```\n\n" - }, - { - "name": "scripts.md", - "id": "/entities/scripts.md", - "url": "/entities/scripts.html", - "title": "Scripts", - "content": "# Scripts\n\nScript are a way to create plugins for otoroshi without deploying them as jar files. With scripts, you just have to store the scala code of your plugins inside the otoroshi datastore and otoroshi will compile and deploy them at startup. You can find all your scripts in the UI at `cog icon / Plugins`. You can find all the documentation about plugins @ref:[here](../plugins/index.md)\n\n@@@ warning\nThe compilation of your plugins can be pretty long and resources consuming. As the compilation happens during otoroshi boot sequence, your instance will be blocked until all plugins have compiled. This behavior can be disabled. If so, the plugins will not work until they have been compiled. Any service using a plugin that is not compiled yet will fail\n@@@\n\nLike any entity, the script has has the following properties\n\n* `id`\n* `plugin name`\n* `plugin description`\n* `tags`\n* `metadata`\n\nAnd you also have\n\n* `type`: the kind of plugin you are building with this script\n* `plugin code`: the code for your plugin\n\n## Compile\n\nYou can use the compile button to check if the code you write in `plugin code` is valid. It will automatically save your script and try to compile. As mentionned earlier, script compilation is quite resource intensive. It will affect your CPU load and your memory consumption. Don't forget to adjust your VM settings accordingly.\n" - }, - { - "name": "service-descriptors.md", - "id": "/entities/service-descriptors.md", - "url": "/entities/service-descriptors.html", - "title": "Service descriptors", - "content": "# Service descriptors\n\nServices or service descriptor, let you declare how to proxy a call from a domain name to another domain name (or multiple domain names). \n\n@@@ div { .centered-img }\n\n@@@\n\nLet’s say you have an API exposed on http://192.168.0.42 and I want to expose it on https://my.api.foo. Otoroshi will proxy all calls to https://my.api.foo and forward them to http://192.168.0.42. While doing that, it will also log everyhting, control accesses, etc.\n\n\n* `Id`: a unique random string to identify your service\n* `Groups`: each service descriptor is attached to a group. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group.\n* `Create a new group`: you can create a new group to host this descriptor\n* `Create dedicated group`: you can create a new group with an auto generated name to host this descriptor\n* `Name`: the name of your service. Only for debug and human readability purposes.\n* `Description`: the description of your service. Only for debug and human readability purposes.\n* `Service enabled`: activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist.\n* `Read only mode`: authorize only GET, HEAD, OPTIONS calls on this service\n* `Maintenance mode`: display a maintainance page when a user try to use the service\n* `Construction mode`: display a construction page when a user try to use the service\n* `Log analytics`: Log analytics events for this service on the servers\n* `Use new http client`: will use Akka Http Client for every request\n* `Detect apikey asap`: If the service is public and you provide an apikey, otoroshi will detect it and validate it. Of course this setting may impact performances because of useless apikey lookups.\n* `Send Otoroshi headers back`: when enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc ...\n* `Override Host header`: when enabled, Otoroshi will automatically set the Host header to corresponding target host\n* `Send X-Forwarded-* headers`: when enabled, Otoroshi will send X-Forwarded-* headers to target\n* `Force HTTPS`: will force redirection to `https://` if not present\n* `Allow HTTP/1.0 requests`: will return an error on HTTP/1.0 request\n* `Use new WebSocket client`: will use the new websocket client for every websocket request\n* `TCP/UDP tunneling`: with this setting enabled, otoroshi will not proxy http requests anymore but instead will create a secured tunnel between a cli on your machine and otoroshi to proxy any tcp connection with all otoroshi security features enabled\n\n### Service exposition settings\n\n* `Exposed domain`: the domain used to expose your service. Should follow pattern: `(http|https)://subdomain?.env?.domain.tld?/root?` or regex `(http|https):\\/\\/(.*?)\\.?(.*?)\\.?(.*?)\\.?(.*)\\/?(.*)`\n* `Legacy domain`: use `domain`, `subdomain`, `env` and `matchingRoot` for routing in addition to hosts, or just use hosts.\n* `Strip path`: when matching, strip the matching prefix from the upstream request URL. Defaults to true\n* `Issue Let's Encrypt cert.`: automatically issue and renew let's encrypt certificate based on domain name. Only if Let's Encrypt enabled in global config.\n* `Issue certificate`: automatically issue and renew a certificate based on domain name\n* `Possible hostnames`: all the possible hostnames for your service\n* `Possible matching paths`: all the possible matching paths for your service\n\n### Redirection\n\n* `Redirection enabled`: enabled the redirection. If enabled, a call to that service will redirect to the chosen URL\n* `Http redirection code`: type of redirection used\n* `Redirect to`: URL used to redirect user when the service is called\n\n### Service targets\n\n* `Redirect to local`: if you work locally with Otoroshi, you may want to use that feature to redirect one specific service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests\n* `Load balancing`: the load balancing algorithm used\n* `Targets`: the list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures\n* `Targets root`: Otoroshi will append this root to any target choosen. If the specified root is `/api/foo`, then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar\n\n### URL Patterns\n\n* `Make service a 'public ui'`: add a default pattern as public routes\n* `Make service a 'private api'`: add a default pattern as private routes\n* `Public patterns`: by default, every services are private only and you'll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use `/.*`\n* `Private patterns`: if you define a public pattern that is a little bit too much, you can make some of public URL private again\n\n### Restrictions\n\n* `Enabled`: enable restrictions\n* `Allow last`: Otoroshi will test forbidden and notFound paths before testing allowed paths\n* `Allowed`: allowed paths\n* `Forbidden`: forbidden paths\n* `Not Found`: not found paths\n\n### Otoroshi exchange protocol\n\n* `Enabled`: when enabled, Otoroshi will try to exchange headers with backend service to ensure no one else can use the service from outside.\n* `Send challenge`: when disbaled, Otoroshi will not check if target service respond with sent random value.\n* `Send info. token`: when enabled, Otoroshi add an additional header containing current call informations\n* `Challenge token version`: version the otoroshi exchange protocol challenge. This option will be set to V2 in a near future.\n* `Info. token version`: version the otoroshi exchange protocol info token. This option will be set to Latest in a near future.\n* `Tokens TTL`: the number of seconds for tokens (state and info) lifes\n* `State token header name`: the name of the header containing the state token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.state)\n* `State token response header name`: the name of the header containing the state response token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.stateresp)\n* `Info token header name`: the name of the header containing the info token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.claim)\n* `Excluded patterns`: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n* `Use same algo.`: when enabled, all JWT token in this section will use the same signing algorithm. If `use same algo.` is disabled, three more options will be displayed to select an algorithm for each step of the calls :\n * Otoroshi to backend\n * Backend to otoroshi\n * Info. token\n\n* `Algo.`: What kind of algorithm you want to use to verify/sign your JWT token with\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: used to verify the token\n* `Base64 encoded secret`: if enabled, the extracted token will be base64 decoded before it is verifier\n\n### Authentication\n\n* `Enforce user authentication`: when enabled, user will be allowed to use the service (UI) only if they are registered users of the chosen authentication module.\n* `Auth. config`: authentication module used to protect the service\n* `Create a new auth config.`: navigate to the creation of authentication module page\n* `all auth config.`: navigate to the authentication pages\n\n* `Excluded patterns`: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n* `Strict mode`: strict mode enabled\n\n### Api keys constraints\n\n* `From basic auth.`: you can pass the api key in Authorization header (ie. from 'Authorization: Basic xxx' header)\n* `Allow client id only usage`: you can pass the api key using client id only (ie. from Otoroshi-Token header)\n* `From custom headers`: you can pass the api key using custom headers (ie. Otoroshi-Client-Id and Otoroshi-Client-Secret headers)\n* `From JWT token`: you can pass the api key using a JWT token (ie. from 'Authorization: Bearer xxx' header)\n\n#### Basic auth. Api Key\n\n* `Custom header name`: the name of the header to get Authorization\n* `Custom query param name`: the name of the query param to get Authorization\n\n#### Client ID only Api Key\n\n* `Custom header name`: the name of the header to get the client id\n* `Custom query param name`: the name of the query param to get the client id\n\n#### Custom headers Api Key\n\n* `Custom client id header name`: the name of the header to get the client id\n* `Custom client secret header name`: the name of the header to get the client secret\n\n#### JWT Token Api Key\n\n* `Secret signed`: JWT can be signed by apikey secret using HMAC algo.\n* `Keypair signed`: JWT can be signed by an otoroshi managed keypair using RSA/EC algo.\n* `Include Http request attrs.`: if enabled, you have to put the following fields in the JWT token corresponding to the current http call (httpPath, httpVerb, httpHost)\n* `Max accepted token lifetime`: the maximum number of second accepted as token lifespan\n* `Custom header name`: the name of the header to get the jwt token\n* `Custom query param name`: the name of the query param to get the jwt token\n* `Custom cookie name`: the name of the cookie to get the jwt token\n\n### Routing constraints\n\n* `All Tags in` : have all of the following tags\n* `No Tags in` : not have one of the following tags\n* `One Tag in` : have at least one of the following tags\n* `All Meta. in` : have all of the following metadata entries\n* `No Meta. in` : not have one of the following metadata entries\n* `One Meta. in` : have at least one of the following metadata entries\n* `One Meta key in` : have at least one of the following key in metadata\n* `All Meta key in` : have all of the following keys in metadata\n* `No Meta key in` : not have one of the following keys in metadata\n\n### CORS support\n\n* `Enabled`: if enabled, CORS header will be check for each incoming request\n* `Allow credentials`: if enabled, the credentials will be sent. Credentials are cookies, authorization headers, or TLS client certificates.\n* `Allow origin`: if enabled, it will indicates whether the response can be shared with requesting code from the given\n* `Max age`: response header indicates how long the results of a preflight request (that is the information contained in the Access-Control-Allow-Methods and Access-Control-Allow-Headers headers) can be cached.\n* `Expose headers`: response header allows a server to indicate which response headers should be made available to scripts running in the browser, in response to a cross-origin request.\n* `Allow headers`: response header is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request.\n* `Allow methods`: response header specifies one or more methods allowed when accessing a resource in response to a preflight request.\n* `Excluded patterns`: by default, when cors is enabled, everything has cors. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n\n#### Related documentations\n\n* @link[Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials) { open=new }\n* @link[Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) { open=new }\n* @link[Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age) { open=new }\n* @link[Access-Control-Allow-Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods) { open=new }\n* @link[Access-Control-Allow-Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers) { open=new }\n\n### JWT tokens verification\n\n* `Verifiers`: list of selected verifiers to apply on the service\n* `Enabled`: if enabled, Otoroshi will enabled each verifier of the previous list\n* `Excluded patterns`: list of routes where the verifiers will not be apply\n\n### Pre Routing\n\nThis part has been deprecated and moved to the plugin section.\n\n### Access validation\nThis part has been deprecated and moved to the plugin section.\n\n### Gzip support\n\n* `Mimetypes allowed list`: gzip only the files that are matching to a format in the list\n* `Mimetypes blocklist`: will not gzip files matching to a format in the list. A possible way is to allowed all format by default by setting a `*` on the `Mimetypes allowed list` and to add the unwanted format in this list.\n* `Compression level`: the compression level where 9 gives us maximum compression but at the slowest speed. The default compression level is 5 and is a good compromise between speed and compression ratio.\n* `Buffer size`: chunking up a stream of bytes into limited size\n* `Chunk threshold`: if the content type of a request reached over the threshold, the response will be chunked\n* `Excluded patterns`: by default, when gzip is enabled, everything has gzip. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n\n### Client settings\n\n* `Use circuit breaker`: use a circuit breaker to avoid cascading failure when calling chains of services. Highly recommended !\n* `Cache connections`: use a cache at host connection level to avoid reconnection time\n* `Client attempts`: specify how many times the client will retry to fetch the result of the request after an error before giving up.\n* `Client call timeout`: specify how long each call should last at most in milliseconds.\n* `Client call and stream timeout`: specify how long each call should last at most in milliseconds for handling the request and streaming the response.\n* `Client connection timeout`: specify how long each connection should last at most in milliseconds.\n* `Client idle timeout`: specify how long each connection can stay in idle state at most in milliseconds.\n* `Client global timeout`: specify how long the global call (with retries) should last at most in milliseconds.\n* `C.breaker max errors`: specify how many errors can pass before opening the circuit breaker\n* `C.breaker retry delay`: specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor\n* `C.breaker backoff factor`: specify the factor to multiply the delay for each retry\n* `C.breaker window`: specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted\n\n#### Custom timeout settings (list)\n\n* `Path`: the path on which the timeout will be active\n* `Client connection timeout`: specify how long each connection should last at most in milliseconds.\n* `Client idle timeout`: specify how long each connection can stay in idle state at most in milliseconds.\n* `Client call and stream timeout`: specify how long each call should last at most in milliseconds for handling the request and streaming the response.\n* `Call timeout`: Specify how long each call should last at most in milliseconds.\n* `Client global timeout`: specify how long the global call (with retries) should last at most in milliseconds.\n\n#### Proxy settings\n\n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n\n### HTTP Headers\n\n* `Additional Headers In`: specify headers that will be added to each client request (from Otoroshi to target). Useful to add authentication.\n* `Additional Headers Out`: specify headers that will be added to each client response (from Otoroshi to client).\n* `Missing only Headers In`: specify headers that will be added to each client request (from Otoroshi to target) if not in the original request.\n* `Missing only Headers Out`: specify headers that will be added to each client response (from Otoroshi to client) if not in the original response.\n* `Remove incoming headers`: remove headers in the client request (from client to Otoroshi).\n* `Remove outgoing headers`: remove headers in the client response (from Otoroshi to client).\n* `Security headers`:\n* `Utility headers`:\n* `Matching Headers`: specify headers that MUST be present on client request to route it (pre routing). Useful to implement versioning.\n* `Headers verification`: verify that some headers has a specific value (post routing)\n\n### Additional settings \n\n* `OpenAPI`: specify an open API descriptor. Useful to display the documentation\n* `Tags`: specify tags for the service\n* `Metadata`: specify metadata for the service. Useful for analytics\n* `IP allowed list`: IP address that can access the service\n* `IP blocklist`: IP address that cannot access the service\n\n### Canary mode\n\n* `Enabled`: Canary mode enabled\n* `Traffic split`: Ratio of traffic that will be sent to canary targets. For instance, if traffic is at 0.2, for 10 request, 2 request will go on canary targets and 8 will go on regular targets.\n* `Targets`: The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures\n * `Target`:\n * `Targets root`: Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar\n* `Campaign stats`:\n* `Use canary targets as standard targets`:\n\n### Healthcheck settings\n\n* `HealthCheck enabled`: to help failing fast, you can activate healthcheck on a specific URL.\n* `HealthCheck url`: the URL to check. Should return an HTTP 200 response. You can also respond with an 'Opun-Health-Check-Logic-Test-Result' header set to the value of the 'Opun-Health-Check-Logic-Test' request header + 42. to make the healthcheck complete.\n\n### Fault injection\n\n* `User facing app.`: if service is set as user facing, Snow Monkey can be configured to not being allowed to create outage on them.\n* `Chaos enabled`: activate or deactivate chaos setting on this service descriptor.\n\n### Custom errors template\n\n* `40x template`: html template displayed when 40x error occurred\n* `50x template`: html template displayed when 50x error occurred\n* `Build mode template`: html template displayed when the build mode is enabled\n* `Maintenance mode template`: html template displayed when the maintenance mode is enabled\n* `Custom messages`: override error message one by one\n\n### Request transformation\n\nThis part has been deprecated and moved to the plugin section.\n\n### Plugins\n\n* `Plugins`:\n \n * `Inject default config`: injects, if present, the default configuration of a selected plugin in the configuration object\n * `Documentation`: link to the documentation website of the plugin\n * `show/hide config. panel`: shows and hides the plugin panel which contains the plugin description and configuration\n* `Excluded patterns`: by default, when plugins are enabled, everything pass in. But sometimes you need to exclude something, so just add regex to matching path you want to exlude.\n* `Configuration`: the configuration of each enabled plugin, split by names and grouped in the same configuration object." - }, - { - "name": "service-groups.md", - "id": "/entities/service-groups.md", - "url": "/entities/service-groups.html", - "title": "Service groups", - "content": "# Service groups\n\nA service group is composed of an unique `id`, a `Group name`, a `Group description`, an `Organization` and a `Team`. As all Otoroshi resources, a service group have a list of tags and metadata associated.\n\n@@@ div { .centered-img }\n\n@@@\n\nThe first instinctive usage of service group is to group a list of services. \n\nWhen it's done, you can authorize an api key on a specific group. Instead of authorize an api key for each service, you can regroup a list of services together, and give authorization on the group (read the page on the api keys and the usage of the `Authorized on.` field).\n\n## Access to the list of service groups\n\nTo visualize and edit the list of groups, you can navigate to your instance on the `https://otoroshi.xxxxx/bo/dashboard/groups` route or click on the cog icon and select the Service groups button.\n\nOnce on the page, you can create a new item, edit an existing service group or delete an existing one.\n\n> When a service group is deleted, the resources associated are not deleted. On the other hand, the service group of associated resources is let empty.\n\n" - }, - { - "name": "tcp-services.md", - "id": "/entities/tcp-services.md", - "url": "/entities/tcp-services.html", - "title": "TCP services", - "content": "# TCP services\n\nTCP service are special kind of otoroshi services meant to proxy pure TCP connections (ssh, database, http, etc)\n\n## Global information\n\n* `Id`: generated unique identifier\n* `TCP service name`: the name of your TCP service\n* `Enabled`: enable and disable the service\n* `TCP service port`: the listening port\n* `TCP service interface`: network interface listen by the service\n* `Tags`: list of tags associated to the service\n* `Metadata`: list of metadata associated to the service\n\n## TLS\n\nthis section controls the TLS exposition of the service\n\n* `TLS mode`\n * `Disabled`: no TLS\n * `PassThrough`: as the target exposes TLS, the call will pass through otoroshi and use target TLS\n * `Enabled`: the service will be exposed using TLS and will chose certificate based on SNI\n* `Client Auth.`\n * `None` no mTLS needed to pass\n * `Want` pass with or without mTLS\n * `Need` need mTLS to pass\n\n## Server Name Indication (SNI)\n\nthis section control how SNI should be treated\n\n* `SNI routing enabled`: if enabled, the server will use the SNI hostname to determine which certificate to present to the client\n* `Forward to target if no SNI match`: if enabled, a call without any SNI match will be forward to the target\n* `Target host`: host of the target called if no SNI\n* `Target ip address`: ip of the target called if no SNI\n* `Target port`: port of the target called if no SNI\n* `TLS call`: encrypt the communication with TLS\n\n## Rules\n\nfor any listening TCP proxy, it is possible to route to multiple targets based on SNI or extracted http host (if proxying http)\n\n* `Matching domain name`: regex used to filter the list of domains where the rule will be applied\n* `Target host`: host of the target\n* `Target ip address`: ip of the target\n* `Target port`: port of the target\n* `TLS call`: enable this flag if the target is exposed using TLS\n" - }, - { - "name": "teams.md", - "id": "/entities/teams.md", - "url": "/entities/teams.html", - "title": "Teams", - "content": "# Teams\n\nIn Otoroshi, all resources are attached to an `Organization` and a `Team`. \n\nA team is composed of an unique `id`, a `name`, a `description` and an `Organization`. As all Otoroshi resources, a Team have a list of tags and metadata associated.\n\nA team have an unique organization and can be use on multiples resources (services, api keys, etc ...).\n\nA connected user on Otoroshi UI has a list of teams and organizations associated. It can be helpful when you want restrict the rights of a connected user.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Access to the list of teams\n\nTo visualize and edit the list of teams, you can navigate to your instance on the `https://otoroshi.xxxxxx/bo/dashboard/teams` route or click on the cog icon and select the teams button.\n\nOnce on the page, you can create a new item, edit an existing team or delete an existing one.\n\n> When a team is deleted, the resources associated are not deleted. On the other hand, the team of associated resources is let empty.\n\n## Entities location\n\nAny otoroshi entity has a location property (`_loc` when serialized to json) explaining where and by whom the entity can be seen. \n\nAn entity can be part of multiple teams in an organization\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": [\n \"team-1\",\n \"team-2\"\n ]\n }\n ...\n}\n```\n\nor all teams\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": [\n \"*\"\n ]\n }\n ...\n}\n```" - }, - { - "name": "features.md", - "id": "/features.md", - "url": "/features.html", - "title": "Features", - "content": "# Features\n\n**Traffic Management**\n\n* Can proxy any HTTP(s) service (apis, webapps, websocket, etc)\n* Can proxy any TCP service (app, database, etc)\n* Traffic mirroring\n* Canary deployments\n* Multiple load-balancing options: RoundRobin, Random, Sticky, Ip Hash, Best Response Time\n* Distributed in-flight request limiting\t\n* Distributed rate limiting \n\n**Services customization**\n\n* Dozens of built-in middlewares (plugins) \n * circuit breakers\n * automatic retries\n * buffering\n * gzip\n * headers manipulation\n * cors\n * etc \n* Custom middleware\n* Higly customizable visibility\n\n**Services Monitoring**\n\n* Active health checks\n* Calls tracing\n* Export alerts and events to external database\n* Real-time traffic metrics\n* Alert mailers\n* Real-time traffic metrics (Datadog, Prometheus, StatsD)\n\n**API security**\n\n* Access management with apikeys and quotas\n* Automatic apikeys secrets rotation\n* HTTPS and TLS\n* mTLS in/out calls \n* Routing constraints\n* Routing restrictions\n* JWT tokens validation and manipulation\n\n**Administration UI**\n\n* Manage and organize all resources\n* Secured users access with Authentication module\n* Traced users actions\n* Dynamic changes at runtime without full reload\n\n**Webapp authentication and security**\n\n* OAuth2.0/2.1 authentication\n* OpenID Connect (OIDC) authentication\n* Internal users management\n* LDAP authentication\n* JWT authentication\n* OAuth 1.0a authentication\n* SAML V2 authentication\n\n**Certificates management**\n\n* Dynamic TLS certificates store \n* Dynamic TLS termination\n* Internal PKI\n* ACME / Let's Encrypt support\n* On-the-fly certificate generation based on a CA certificate without request loss\n\n**Performances and testing**\n\n* Chaos engineering\n* Clustering with encrypted communication\n* Scalability\n\n**Kubernetes integration**\n\n* Standard Ingress controller\n* Custom Ingress controller\n * Manage Otoroshi resources from Kubernetes\n* Validation of resources via webhook\n* Service Mesh for easy service-to-service communication\n\n**Developpers portal**\n\n* Using @link:[Daikoku](https://maif.github.io/daikoku/manual/index.html) { open=new }\n" - }, - { - "name": "getting-started.md", - "id": "/getting-started.md", - "url": "/getting-started.html", - "title": "Getting Started", - "content": "# Getting Started\n\n- [Protect the access to your api with the Otoroshi management of api keys](#protect-the-access-to-your-api-with-the-otoroshi-management-of-api-keys)\n- [Secure your web app in 5 minutes with an authentication](#secure-your-web-app-in-5-minutes-with-an-authentication)\n\nDownload the latest jar of Otoroshi\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nOnce downloading, run Otoroshi.\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\n## Protect the access to your api with the Otoroshi management of api keys\n\nCreate a service, exposed on `http://myapi.oto.tools:8080`, which will forward all requests to the mirror `https://mirror.otoroshi.io`.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n-d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"myapi\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"myapi\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\"],\"privatePatterns\":[\"\\/.*\"],\"kind\":\"ServiceDescriptor\"}' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nTry to call this service. You should receive an error from Otoroshi about a missing api key in our request.\n\n```sh\ncurl 'http://myapi.oto.tools:8080'\n```\n\nCreate your first api key with a quota of 10 calls by day and month.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/apikeys' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret \\\n-d @- <<'EOF'\n{\n \"clientId\": \"my-first-apikey-id\",\n \"clientSecret\": \"my-first-apikey-secret\",\n \"clientName\": \"my-first-apikey\",\n \"description\": \"my-first-apikey-description\",\n \"authorizedGroup\": \"default\",\n \"enabled\": true,\n \"throttlingQuota\": 10,\n \"dailyQuota\": 10,\n \"monthlyQuota\": 10\n}\nEOF\n```\n\nCall your api with the generated apikey.\n\n```sh\ncurl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret\n```\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.otoroshi.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"authorization\": \"Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==\",\n \"otoroshi-request-id\": \"1465298507974836306\",\n \"otoroshi-proxied-host\": \"myapi.oto.tools:8080\",\n \"otoroshi-request-timestamp\": \"2021-11-29T13:36:02.888+01:00\",\n },\n \"body\": \"\"\n}\n```\n\nCheck your remaining quotas\n\n```sh\ncurl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret --include\n```\n\nThis should output these following Otoroshi headers\n\n```json\nOtoroshi-Daily-Calls-Remaining: 6\nOtoroshi-Monthly-Calls-Remaining: 6\n```\n\nKeep calling the api and confirm that Otoroshi is sending you an apikey exceeding quota error\n\n\n```json\n{ \n \"Otoroshi-Error\": \"You performed too much requests\"\n}\n```\n\nWell done, you have secured your first api with the apikeys system with limited call quotas.\n\n## Secure your web app in 5 minutes with an authentication\n\nCreate an in-memory authentication module, with one registered user, to protect your service.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/auths' \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\n \"type\":\"basic\",\n \"id\":\"auth_mod_in_memory_auth\",\n \"name\":\"in-memory-auth\",\n \"desc\":\"in-memory-auth\",\n \"users\":[\n {\n \"name\":\"User Otoroshi\",\n \"password\":\"$2a$10$oIf4JkaOsfiypk5ZK8DKOumiNbb2xHMZUkYkuJyuIqMDYnR/zXj9i\",\n \"email\":\"user@foo.bar\",\n \"metadata\":{\n \"username\":\"roger\"\n },\n \"tags\":[\"foo\"],\n \"webauthn\":null,\n \"rights\":[{\n \"tenant\":\"*:r\",\n \"teams\":[\"*:r\"]\n }]\n }\n ],\n \"sessionCookieValues\":{\n \"httpOnly\":true,\n \"secure\":false\n }\n}\nEOF\n```\n\nThen create a service secure by the previous authentication module, which proxies `google.fr` on `webapp.oto.tools`.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n-d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"webapp\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"webapp\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"google.fr\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\\/.*\"],\"privatePatterns\":[\"\"],\"kind\":\"ServiceDescriptor\",\"authConfigRef\":\"auth_mod_in_memory_auth\",\"privateApp\":true}' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nNavigate to http://webapp.oto.tools:8080, login with `user@foo.bar/password` and check that you're redirect to `google` page.\n\nWell done! You completed the discovery tutorial." - }, - { - "name": "custom-initial-state.md", - "id": "/how-to-s/custom-initial-state.md", - "url": "/how-to-s/custom-initial-state.html", - "title": "Initial state customization", - "content": "# Initial state customization\n\nwhen you start otoroshi for the first time, some basic entities will be created and stored in the datastore in order to make your instance work properly. However it might not be enough for your use case but you do want to bother with restoring a complete otoroshi export.\n\nIn order to make state customization easy, otoroshi provides the config. key `otoroshi.initialCustomization`, overriden by the env. variable `OTOROSHI_INITIAL_CUSTOMIZATION`\n\nThe expected structure is the following :\n\n```javascript\n{\n \"config\": { ... },\n \"admins\": [],\n \"simpleAdmins\": [],\n \"serviceGroups\": [],\n \"apiKeys\": [],\n \"serviceDescriptors\": [],\n \"errorTemplates\": [],\n \"jwtVerifiers\": [],\n \"authConfigs\": [],\n \"certificates\": [],\n \"clientValidators\": [],\n \"scripts\": [],\n \"tcpServices\": [],\n \"dataExporters\": [],\n \"tenants\": [],\n \"teams\": []\n}\n```\n\nin this structure, everything is optional. For every array property, items will be added to the datastore. For the global config. object, you can just add the parts that you need, and they will be merged with the existing config. object of the datastore.\n\n## Customize the global config.\n\nfor instance, if you want to customize the behavior of the TLS termination, you can use the following :\n\n```sh\nexport OTOROSHI_INITIAL_CUSTOMIZATION='{\"config\":{\"tlsSettings\":{\"defaultDomain\":\"www.foo.bar\",\"randomIfNotFound\":false}}'\n```\n\n## Customize entities\n\nif you want to add apikeys at first boot \n\n```sh\nexport OTOROSHI_INITIAL_CUSTOMIZATION='{\"apikeys\":[{\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"clientId\":\"ksVlQ2KlZm0CnDfP\",\"clientSecret\":\"usZYbE1iwSsbpKY45W8kdbZySj1M5CWvFXe0sPbZ0glw6JalMsgorDvSBdr2ZVBk\",\"clientName\":\"awesome-apikey\",\"description\":\"the awesome apikey\",\"authorizedGroup\":\"default\",\"authorizedEntities\":[\"group_default\"],\"enabled\":true,\"readOnly\":false,\"allowClientIdOnly\":false,\"throttlingQuota\":10000000,\"dailyQuota\":10000000,\"monthlyQuota\":10000000,\"constrainedServicesOnly\":false,\"restrictions\":{\"enabled\":false,\"allowLast\":true,\"allowed\":[],\"forbidden\":[],\"notFound\":[]},\"rotation\":{\"enabled\":false,\"rotationEvery\":744,\"gracePeriod\":168,\"nextSecret\":null},\"validUntil\":null,\"tags\":[],\"metadata\":{}}]}'\n```\n" - }, - { - "name": "custom-log-levels.md", - "id": "/how-to-s/custom-log-levels.md", - "url": "/how-to-s/custom-log-levels.html", - "title": "Log levels customization", - "content": "# Log levels customization\n\nIf you want to customize the log level of your otoroshi instances, it's pretty easy to do it using environment variables or configuration file.\n\n## Customize log level for one logger with configuration file\n\nLet say you want to see `DEBUG` messages from the logger `otoroshi-http-handler`.\n\nThen you just have to declare in your otoroshi configuration file\n\n```\notoroshi.loggers {\n ...\n otoroshi-http-handler = \"DEBUG\"\n ...\n}\n```\n\npossible levels are `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`. Default one is `WARN`.\n\n## Customize log level for one logger with environment variable\n\nLet say you want to see `DEBUG` messages from the logger `otoroshi-http-handler`.\n\nThen you just have to declare an environment variable named `OTOROSHI_LOGGERS_OTOROSHI_HTTP_HANDLER` with value `DEBUG`. The rule is \n\n```scala\n\"OTOROSHI_LOGGERS_\" + loggerName.toUpperCase().replace(\"-\", \"_\")\n```\n\npossible levels are `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`. Default one is `WARN`.\n\n## List of loggers\n\n* [`otoroshi-error-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-error-handler%22%29)\n* [`otoroshi-http-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler%22%29)\n* [`otoroshi-http-handler-debug`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler-debug%22%29)\n* [`otoroshi-websocket-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket-handler%22%29)\n* [`otoroshi-websocket`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket%22%29)\n* [`otoroshi-websocket-handler-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket-handler-actor%22%29)\n* [`otoroshi-snowmonkey`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snowmonkey%22%29)\n* [`otoroshi-circuit-breaker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-circuit-breaker%22%29)\n* [`otoroshi-circuit-breaker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-circuit-breaker%22%29)\n* [`otoroshi-worker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-worker%22%29)\n* [`otoroshi-http-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler%22%29)\n* [`otoroshi-auth-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-controller%22%29)\n* [`otoroshi-swagger-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-swagger-controller%22%29)\n* [`otoroshi-u2f-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-u2f-controller%22%29)\n* [`otoroshi-backoffice-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-backoffice-api%22%29)\n* [`otoroshi-health-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-health-api%22%29)\n* [`otoroshi-stats-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-stats-api%22%29)\n* [`otoroshi-admin-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-admin-api%22%29)\n* [`otoroshi-auth-modules-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-modules-api%22%29)\n* [`otoroshi-certificates-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificates-api%22%29)\n* [`otoroshi-pki`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-pki%22%29)\n* [`otoroshi-scripts-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-scripts-api%22%29)\n* [`otoroshi-analytics-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-api%22%29)\n* [`otoroshi-import-export-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-import-export-api%22%29)\n* [`otoroshi-templates-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-templates-api%22%29)\n* [`otoroshi-teams-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-teams-api%22%29)\n* [`otoroshi-events-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-events-api%22%29)\n* [`otoroshi-canary-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-canary-api%22%29)\n* [`otoroshi-data-exporter-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-api%22%29)\n* [`otoroshi-services-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-services-api%22%29)\n* [`otoroshi-tcp-service-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-service-api%22%29)\n* [`otoroshi-tenants-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tenants-api%22%29)\n* [`otoroshi-global-config-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-config-api%22%29)\n* [`otoroshi-apikeys-fs-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-fs-api%22%29)\n* [`otoroshi-apikeys-fg-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-fg-api%22%29)\n* [`otoroshi-apikeys-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-api%22%29)\n* [`otoroshi-statsd-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-statsd-actor%22%29)\n* [`otoroshi-snow-monkey-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snow-monkey-api%22%29)\n* [`otoroshi-jobs-eventstore-checker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jobs-eventstore-checker%22%29)\n* [`otoroshi-initials-certs-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-initials-certs-job%22%29)\n* [`otoroshi-alert-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alert-actor%22%29)\n* [`otoroshi-alert-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alert-actor-supervizer%22%29)\n* [`otoroshi-alerts`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alerts%22%29)\n* [`otoroshi-apikeys-secrets-rotation-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-secrets-rotation-job%22%29)\n* [`otoroshi-loader`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-loader%22%29)\n* [`otoroshi-api-action`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-api-action%22%29)\n* [`otoroshi-api-action`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-api-action%22%29)\n* [`otoroshi-analytics-writes-elastic`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-writes-elastic%22%29)\n* [`otoroshi-analytics-reads-elastic`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-reads-elastic%22%29)\n* [`otoroshi-events-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-events-actor-supervizer%22%29)\n* [`otoroshi-data-exporter`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter%22%29)\n* [`otoroshi-data-exporter-update-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-update-job%22%29)\n* [`otoroshi-kafka-wrapper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-kafka-wrapper%22%29)\n* [`otoroshi-kafka-connector`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-kafka-connector%22%29)\n* [`otoroshi-analytics-webhook`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-webhook%22%29)\n* [`otoroshi-jobs-software-updates`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jobs-software-updates%22%29)\n* [`otoroshi-analytics-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-actor%22%29)\n* [`otoroshi-analytics-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-actor-supervizer%22%29)\n* [`otoroshi-analytics-event`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-event%22%29)\n* [`otoroshi-env`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-env%22%29)\n* [`otoroshi-script-compiler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script-compiler%22%29)\n* [`otoroshi-script-manager`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script-manager%22%29)\n* [`otoroshi-script`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-custom-timeouts`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-custom-timeouts%22%29)\n* [`otoroshi-client-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-client-config%22%29)\n* [`otoroshi-canary`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-canary%22%29)\n* [`otoroshi-redirection-settings`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redirection-settings%22%29)\n* [`otoroshi-service-descriptor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-descriptor%22%29)\n* [`otoroshi-service-descriptor-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-descriptor-datastore%22%29)\n* [`otoroshi-console-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-console-mailer%22%29)\n* [`otoroshi-mailgun-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mailgun-mailer%22%29)\n* [`otoroshi-mailjet-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mailjet-mailer%22%29)\n* [`otoroshi-sendgrid-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-sendgrid-mailer%22%29)\n* [`otoroshi-generic-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-generic-mailer%22%29)\n* [`otoroshi-clevercloud-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-clevercloud-client%22%29)\n* [`otoroshi-metrics`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-metrics%22%29)\n* [`otoroshi-gzip-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-gzip-config%22%29)\n* [`otoroshi-regex-pool`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-regex-pool%22%29)\n* [`otoroshi-ws-client-chooser`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ws-client-chooser%22%29)\n* [`otoroshi-akka-ws-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-akka-ws-client%22%29)\n* [`otoroshi-http-implicits`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-implicits%22%29)\n* [`otoroshi-service-group`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-group%22%29)\n* [`otoroshi-data-exporter-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-config%22%29)\n* [`otoroshi-data-exporter-config-migration-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-config-migration-job%22%29)\n* [`otoroshi-lets-encrypt-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lets-encrypt-helper%22%29)\n* [`otoroshi-apkikey`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apkikey%22%29)\n* [`otoroshi-error-template`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-error-template%22%29)\n* [`otoroshi-job-manager`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-job-manager%22%29)\n* [`otoroshi-plugins-internal-eventlistener-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-internal-eventlistener-actor%22%29)\n* [`otoroshi-global-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-config%22%29)\n* [`otoroshi-jwks`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jwks%22%29)\n* [`otoroshi-jwt-verifier`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jwt-verifier%22%29)\n* [`otoroshi-global-jwt-verifier`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-jwt-verifier%22%29)\n* [`otoroshi-snowmonkey-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snowmonkey-config%22%29)\n* [`otoroshi-webauthn-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-webauthn-admin-datastore%22%29)\n* [`otoroshi-webauthn-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-webauthn-admin-datastore%22%29)\n* [`otoroshi-leveldb-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-leveldb-datastores%22%29)\n* [`otoroshi-service-datatstore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-datatstore%22%29)\n* [`otoroshi-cassandra-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cassandra-datastores%22%29)\n* [`otoroshi-redis-like-store`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redis-like-store%22%29)\n* [`otoroshi-globalconfig-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-globalconfig-datastore%22%29)\n* [`otoroshi-mongo-redis`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mongo-redis%22%29)\n* [`otoroshi-mongo-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mongo-datastores%22%29)\n* [`otoroshi-reactive-pg-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-reactive-pg-datastores%22%29)\n* [`otoroshi-reactive-pg-kv`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-reactive-pg-kv%22%29)\n* [`otoroshi-cassandra-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cassandra-datastores%22%29)\n* [`otoroshi-apikey-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikey-datastore%22%29)\n* [`otoroshi-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-datastore%22%29)\n* [`otoroshi-certificate-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificate-datastore%22%29)\n* [`otoroshi-simple-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-simple-admin-datastore%22%29)\n* [`otoroshi-atomic-in-memory-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-atomic-in-memory-datastore%22%29)\n* [`otoroshi-lettuce-redis`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lettuce-redis%22%29)\n* [`otoroshi-lettuce-redis-cluster`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lettuce-redis-cluster%22%29)\n* [`otoroshi-redis-lettuce-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redis-lettuce-datastores%22%29)\n* [`otoroshi-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-datastores%22%29)\n* [`otoroshi-file-db-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-file-db-datastores%22%29)\n* [`otoroshi-http-db-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-db-datastores%22%29)\n* [`otoroshi-s3-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-s3-datastores%22%29)\n* [`PluginDocumentationGenerator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22PluginDocumentationGenerator%22%29)\n* [`otoroshi-health-checker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-health-checker%22%29)\n* [`otoroshi-healthcheck-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-healthcheck-job%22%29)\n* [`otoroshi-healthcheck-local-cache-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-healthcheck-local-cache-job%22%29)\n* [`otoroshi-plugins-response-cache`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-response-cache%22%29)\n* [`otoroshi-oidc-apikey-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-oidc-apikey-config%22%29)\n* [`otoroshi-plugins-maxmind-geolocation-info`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-maxmind-geolocation-info%22%29)\n* [`otoroshi-plugins-ipstack-geolocation-info`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-ipstack-geolocation-info%22%29)\n* [`otoroshi-plugins-maxmind-geolocation-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-maxmind-geolocation-helper%22%29)\n* [`otoroshi-plugins-user-agent-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-user-agent-helper%22%29)\n* [`otoroshi-plugins-user-agent-extractor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-user-agent-extractor%22%29)\n* [`otoroshi-global-el`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-el%22%29)\n* [`otoroshi-plugins-oauth1-caller-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-oauth1-caller-plugin%22%29)\n* [`otoroshi-dynamic-sslcontext`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-dynamic-sslcontext%22%29)\n* [`otoroshi-plugins-access-log-clf`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-access-log-clf%22%29)\n* [`otoroshi-plugins-access-log-json`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-access-log-json%22%29)\n* [`otoroshi-plugins-kafka-access-log`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kafka-access-log%22%29)\n* [`otoroshi-plugins-kubernetes-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-client%22%29)\n* [`otoroshi-plugins-kubernetes-ingress-controller-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-ingress-controller-job%22%29)\n* [`otoroshi-plugins-kubernetes-ingress-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-ingress-sync%22%29)\n* [`otoroshi-plugins-kubernetes-crds-controller-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-crds-controller-job%22%29)\n* [`otoroshi-plugins-kubernetes-crds-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-crds-sync%22%29)\n* [`otoroshi-cluster`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cluster%22%29)\n* [`otoroshi-crd-validator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-crd-validator%22%29)\n* [`otoroshi-sidecar-injector`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-sidecar-injector%22%29)\n* [`otoroshi-plugins-kubernetes-cert-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-cert-sync%22%29)\n* [`otoroshi-plugins-kubernetes-to-otoroshi-certs-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-to-otoroshi-certs-job%22%29)\n* [`otoroshi-plugins-otoroshi-certs-to-kubernetes-secrets-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-otoroshi-certs-to-kubernetes-secrets-job%22%29)\n* [`otoroshi-apikeys-workflow-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-workflow-job%22%29)\n* [`otoroshi-cert-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert-helper%22%29)\n* [`otoroshi-certificates-ocsp`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificates-ocsp%22%29)\n* [`otoroshi-claim`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-claim%22%29)\n* [`otoroshi-cert`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert%22%29)\n* [`otoroshi-ssl-provider`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ssl-provider%22%29)\n* [`otoroshi-cert-data`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert-data%22%29)\n* [`otoroshi-client-cert-validator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-client-cert-validator%22%29)\n* [`otoroshi-ssl-implicits`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ssl-implicits%22%29)\n* [`otoroshi-saml-validator-utils`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-saml-validator-utils%22%29)\n* [`otoroshi-global-saml-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-saml-config%22%29)\n* [`otoroshi-plugins-hmac-caller-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hmac-caller-plugin%22%29)\n* [`otoroshi-plugins-hmac-access-validator-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hmac-access-validator-plugin%22%29)\n* [`otoroshi-plugins-hasallowedusersvalidator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hasallowedusersvalidator%22%29)\n* [`otoroshi-auth-module-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-module-config%22%29)\n* [`otoroshi-basic-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-basic-auth-config%22%29)\n* [`otoroshi-ldap-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ldap-auth-config%22%29)\n* [`otoroshi-plugins-jsonpath-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-jsonpath-helper%22%29)\n* [`otoroshi-global-oauth2-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-oauth2-config%22%29)\n* [`otoroshi-global-oauth2-module`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-oauth2-module%22%29)\n* [`otoroshi-ldap-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ldap-auth-config%22%29)\n" - }, - { - "name": "end-to-end-mtls.md", - "id": "/how-to-s/end-to-end-mtls.md", - "url": "/how-to-s/end-to-end-mtls.html", - "title": "End-to-end mTLS", - "content": "# End-to-end mTLS\n\nIf you want to use MTLS on otoroshi, you first need to enable it. It is not enabled by default as it will make TLS handshake way heavier. \nTo enable it just change the following config :\n\n```sh\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```sh\nSSL_OUTSIDE_CLIENT_AUTH=None|Want|Need\n```\n\nYou can use the `Want` setup if you cant to have both mtls on some services and no mtls on other services.\n\nYou can also change the trusted CA list sent in the handshake certificate request from the `Danger Zone` in `Tls Settings`.\n\nOtoroshi support mutual TLS out of the box. mTLS from client to Otoroshi and from Otoroshi to targets are supported. In this article we will see how to configure Otoroshi to use end-to-end mTLS. All code and files used in this articles can be found on the [Otoroshi github](https://github.com/MAIF/otoroshi/tree/master/demos/mtls)\n\n### Create certificates\n\nBut first we need to generate some certificates to make the demo work\n\n```sh\nmkdir mtls-demo\ncd mtls-demo\nmkdir ca\nmkdir server\nmkdir client\n\n# create a certificate authority key, use password as pass phrase\nopenssl genrsa -out ./ca/ca-backend.key 4096\n# remove pass phrase\nopenssl rsa -in ./ca/ca-backend.key -out ./ca/ca-backend.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key ./ca/ca-backend.key -out ./ca/ca-backend.cer -subj \"/CN=MTLSB\"\n\n\n# create a certificate authority key, use password as pass phrase\nopenssl genrsa -out ./ca/ca-frontend.key 2048\n# remove pass phrase\nopenssl rsa -in ./ca/ca-frontend.key -out ./ca/ca-frontend.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key ./ca/ca-frontend.key -out ./ca/ca-frontend.cer -subj \"/CN=MTLSF\"\n\n\n# now create the backend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.backend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.backend.oto.tools.key -out ./server/_.backend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.backend.oto.tools.key -sha256 -out ./server/_.backend.oto.tools.csr -subj \"/CN=*.backend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.oto.tools.cer\n# verify the certificate, should output './server/_.backend.oto.tools.cer: OK'\nopenssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.oto.tools.cer\n\n\n# now create the frontend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.frontend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.frontend.oto.tools.key -out ./server/_.frontend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.frontend.oto.tools.key -sha256 -out ./server/_.frontend.oto.tools.csr -subj \"/CN=*.frontend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.oto.tools.cer\n# verify the certificate, should output './server/_.frontend.oto.tools.cer: OK'\nopenssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.cer\n\n\n# now create the client cert key for backend, use password as pass phrase\nopenssl genrsa -out ./client/_.backend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.csr -subj \"/CN=*.backend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.oto.tools.cer\n# generate a pem version of the cert and key, use password as password\nopenssl x509 -in client/_.backend.oto.tools.cer -out client/_.backend.oto.tools.pem -outform PEM\n\n\n# now create the client cert key for frontend, use password as pass phrase\nopenssl genrsa -out ./client/_.frontend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.csr -subj \"/CN=*.frontend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.oto.tools.cer\n# generate a pkcs12 version of the cert and key, use password as password\n# openssl pkcs12 -export -clcerts -in client/_.frontend.oto.tools.cer -inkey client/_.frontend.oto.tools.key -out client/_.frontend.oto.tools.p12\nopenssl x509 -in client/_.frontend.oto.tools.cer -out client/_.frontend.oto.tools.pem -outform PEM\n```\n\nOnce it's done, you should have something like\n\n```sh\n$ tree\n.\n├── backend.js\n├── ca\n│   ├── ca-backend.cer\n│   ├── ca-backend.key\n│   ├── ca-frontend.cer\n│   └── ca-frontend.key\n├── client\n│   ├── _.backend.oto.tools.cer\n│   ├── _.backend.oto.tools.csr\n│   ├── _.backend.oto.tools.key\n│   ├── _.backend.oto.tools.pem\n│   ├── _.frontend.oto.tools.cer\n│   ├── _.frontend.oto.tools.csr\n│   ├── _.frontend.oto.tools.key\n│   └── _.frontend.oto.tools.pem\n└── server\n ├── _.backend.oto.tools.cer\n ├── _.backend.oto.tools.csr\n ├── _.backend.oto.tools.key\n ├── _.frontend.oto.tools.cer\n ├── _.frontend.oto.tools.csr\n └── _.frontend.oto.tools.key\n\n3 directories, 18 files\n```\n\n### The backend service \n\nnow, let's create a backend service using nodejs. Create a file named `backend.js`\n\n```sh\ntouch backend.js\n```\n\nand put the following content\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nconst options = { \n key: fs.readFileSync('./server/_.backend.oto.tools.key'), \n cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n}; \n\nconst server = https.createServer(options, (req, res) => { \n res.writeHead(200, {\n 'Content-Type': 'application/json'\n }); \n res.end(JSON.stringify({ message: 'Hello World!' }) + \"\\n\"); \n}).listen(8444);\n\nconsole.log('Server listening:', `http://localhost:${server.address().port}`);\n```\n\nto run the server, just do \n\n```sh\nnode ./backend.js\n```\n\nnow you can try your server with\n\n```sh\ncurl --cacert ./ca/ca-backend.cer 'https://api.backend.oto.tools:8444/'\n```\n\nThis should output :\n```json\n{ \"message\": \"Hello World!\" }\n```\n\nnow modify your backend server to ensure that the client provides a client certificate like:\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nconst options = { \n key: fs.readFileSync('./server/_.backend.oto.tools.key'), \n cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nconst server = https.createServer(options, (req, res) => { \n console.log('Client certificate CN: ', req.socket.getPeerCertificate().subject.CN);\n res.writeHead(200, {\n 'Content-Type': 'application/json'\n }); \n res.end(JSON.stringify({ message: 'Hello World!' }) + \"\\n\"); \n}).listen(8444);\n\nconsole.log('Server listening:', `http://localhost:${server.address().port}`);\n```\n\nyou can test your new server with\n\n```sh\ncurl \\\n --cacert ./ca/ca-backend.cer \\\n --cert ./client/_.backend.oto.tools.pem \\\n --key ./client/_.backend.oto.tools.key 'https://api.backend.oto.tools:8444/'\n```\n\nthe output should be :\n\n```json\n{ \"message\": \"Hello World!\" }\n```\n\n### Otoroshi setup\n\nDownload the latest version of the Otoroshi jar and run it like\n\n```sh\n java \\\n -Dotoroshi.adminPassword=password \\\n -Dotoroshi.ssl.fromOutside.clientAuth=Want \\\n -jar -Dotoroshi.storage=file otoroshi.jar\n\n[info] otoroshi-env - Admin API exposed on http://otoroshi-api.oto.tools:8080\n[info] otoroshi-env - Admin UI exposed on http://otoroshi.oto.tools:8080\n[info] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[info] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[info] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / password\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n[info] p.c.s.AkkaHttpServer - Listening for HTTPS on /0:0:0:0:0:0:0:0:8443\n[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...\n```\n\nand log into otoroshi with the tuple `admin@otoroshi.io / password` displayed in the logs. \n\nOnce logged in, navigate to the services pages and create a new item.\n\n* Jump to the `Service exposition settings` and add `http://api.frontend.oto.tools` as `Exposed domain`. \n* Navigate to the `Service targets` and add the following url `https://api.backend.oto.tools:8444/` to redirect our call to the previous created backend. \n* End this step by exposing the service as `Public UI` on the `URL Patterns` section.\n\nand test it\n\n```sh\ncurl 'http://api.frontend.oto.tools:8080/'\n```\n\nThis should output :\n```json\n{\"Otoroshi-Error\": \"Something went wrong, you should try later. Thanks for your understanding.\"}\n```\n\nyou should get an error due to the fact that Otoroshi doesn't know about the server certificate or the client certificate expected by the server.\n\nWe have to add the client certificate for `https://api.backend.oto.tools` to Otoroshi. \n\nGo to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of `./client/_.backend.oto.tools.cer` and `./client/_.backend.oto.tools.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nIf you don't want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.\n\n```sh\ncat ./server/_.backend.oto.tools.cer ./ca/ca-backend.cer ./server/_.backend.oto.tools.key | curl \\\n -H 'Content-Type: text/plain' -X POST \\\n --data-binary @- \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n http://otoroshi-api.oto.tools:8080/api/certificates/_bundle \n```\n\nand retry the following curl command \n\n```sh\ncurl 'http://api.frontend.oto.tools:8080/'\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\nnow we have to expose `https://api.frontend.oto.tools:8443` using otoroshi. \n\nGo to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of `./server/_.frontend.oto.tools.cer` and `./server/_.frontend.oto.tools.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nIf you don't want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.\n\n```sh\ncat ./server/_.frontend.oto.tools.cer ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.key | curl \\\n -H 'Content-Type: text/plain' -X POST \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n --data-binary @- \\\n http://otoroshi-api.oto.tools:8080/api/certificates/_bundle\n```\n\nand try the following command\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\nnow we have to enforce the fact that we want client certificate for `api.frontend.oto.tools`. To do that, we have to add a `Client Validator Only` plugin on the `api.frontend.oto.tools` service. Scroll to the last section called `Plugins` and select the `Client validator only` in the list.\n\nnow if you retry \n\n```sh\ncurl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'\n```\nthe output should be\n\n```json\n{\"Otoroshi-Error\":\"bad request\"}\n```\n\nyou should get an error because no client cert. is passed with the request. But if you pass the `./client/_.frontend.oto.tools.csr` client cert and the key in your curl call\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\n### Client certificate matching plugin\n\nOtoroshi can restrict and check all incoming client certificates on a service.\n\nScroll to the `Plugins` section and select the `Client certificate matching` plugin. Then, click on the `show config. panel` and inject the default configuration of the plugin (by clicking on `Inject default config.`).\n\nSave the service and retry your call again.\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"Otoroshi-Error\":\"bad request\"}\n```\n\nOur client certificate is not matched by Otoroshi. We have to add the subject DN in the configuration of the `Client certificate matching` plugin to authorize it.\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"serialNumbers\": [],\n \"subjectDNs\": [\n \"CN=*.frontend.oto.tools\"\n ],\n \"issuerDNs\": [],\n \"regexSubjectDNs\": [],\n \"regexIssuerDNs\": []\n }\n}\n```\n\nSave the service and retry your call again.\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\n\n" - }, - { - "name": "export-alerts-using-mailgun.md", - "id": "/how-to-s/export-alerts-using-mailgun.md", - "url": "/how-to-s/export-alerts-using-mailgun.html", - "title": "Send alerts using mailgun", - "content": "# Send alerts using mailgun\n\nAll Otoroshi alerts can be send on different channels.\nOne of the ways is to send a group of specific alerts via emails.\n\nTo enable this behaviour, let's start by create an exporter of events.\n\nIn this tutorial, we will admit that you already have a mailgun account with an API key and a domain.\n\n## Create an Mailgun exporter\n\nLet's create an exporter. The exporter will export by default all events generated by Otoroshi.\n\n1. Go ahead, and navigate to http://otoroshi.oto.tools:8080\n2. Click on the cog icon on the top right\n3. Then `Exporters` button\n4. And add a new configuration when clicking on the `Add item` button\n5. Select the `mailer` in the `type` selector field\n6. Jump to `Exporter config` and select the `Mailgun` option\n7. Set the following values:\n* `EU` : false/true depending on your mailgun configuratin\n* `Mailgun api key` : your-mailgun-api-key\n* `Mailgun domain` : your-mailgun-domain\n* `Email addresses` : list of the recipient adresses\n\nWith this configuration, all Otoroshi events will be send to your listed addresses (we don't recommended to do that).\n\nTo filter events on `Alerts` type, we need to add the following configuration inside the `Filtering and projection` section (if you want to deep learn about this section, read this @ref:[part](../entities/data-exporters.md#matching-and-projections)).\n\n```json\n{\n \"include\": [\n { \"@type\": \"AlertEvent\" }\n ],\n \"exclude\": []\n}\n``` \n\nSave at the bottom page and enable the exporter (on the top of the page or in list of exporters). We will need to wait few seconds to receive the first alerts.\n\nThe **projection** field can be useful in the case you want to filter the fields contained in each alert sent.\n\nThe `Projection` field is a json where you can list the fields to keep for each alert.\n\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nWith this example, only `@type`, `@timestamp` and `@id` will be sent to the addresses of your recipients." - }, - { - "name": "export-events-to-elastic.md", - "id": "/how-to-s/export-events-to-elastic.md", - "url": "/how-to-s/export-events-to-elastic.html", - "title": "Export events to Elasticsearch", - "content": "# Export events to Elasticsearch\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Deploy a Elasticsearch and kibana stack on Docker\n\nLet's start by creating an Elasticsearch and Kibana stack on our machine (if it's already done for you, you can skip this section).\n\nTo start an Elasticsearch container for development or testing, run:\n\n```sh\ndocker network create elastic\ndocker pull docker.elastic.co/elasticsearch/elasticsearch:7.15.1\ndocker run --name es01-test --net elastic -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co/elasticsearch/elasticsearch:7.15.1\n```\n\n```sh\ndocker pull docker.elastic.co/kibana/kibana:7.15.1\ndocker run --name kib01-test --net elastic -p 5601:5601 -e \"ELASTICSEARCH_HOSTS=http://es01-test:9200\" docker.elastic.co/kibana/kibana:7.15.1\n```\n\nTo access Kibana, go to @link:[http://localhost:5601](http://localhost:5601) { open=new }.\n\n### Create an Elasticsearch exporter\n\nLet's create an exporter. The exporter will export by default all events generated by Otoroshi.\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n2. Click on the cog icon on the top right\n3. Then `Exporters` button\n4. And add a new configuration when clicking on the `Add item` button\n5. Select the `elastic` in the `type` selector field\n6. Jump to `Exporter config`\n7. Set the following values: `Cluster URI` -> `http://localhost:9200`\n\nThen test your configuration by clicking on the `Check connection` button. This should output a modal with the Elasticsearch version and the number of loaded docs.\n\nSave at the bottom of the page and enable the exporter (on the top of the page or in list of exporters).\n\n### Testing your configuration\n\nOne simple way to test is to setup the reading of our Elasticsearch instance by Otoroshi.\n\nNavigate to the danger zone (click on the cog on the top right and scroll to `danger zone`). Jump to the `Analytics: Elastic dashboard datasource (read)` section.\n\nSet the following values : `Cluster URI` -> `http://localhost:9200`\n\nThen click on the `Check connection`. This should ouput the same result as the previous part. Save the global configuration and navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/stats](http://otoroshi.oto.tools:8080/bo/dashboard/stats) { open=new }.\n\nThis should output a list of graphs.\n\n### Advanced usage\n\nBy default, an exporter handle all events from Otoroshi. In some case, you need to filter the events to send to elasticsearch.\n\nTo filter the events, jump to the `Filtering and projection` field in exporter view. Otoroshi supports to include a kind of events or to exclude a list of events (if you want to deep learn about this section, read this @ref:[part](../entities/data-exporters.md#matching-and-projections)). \n\nAn example which keep only events with a field `@type` of value `AlertEvent`:\n```json\n{\n \"include\": [\n { \"@type\": \"AlertEvent\" }\n ],\n \"exclude\": []\n}\n```\nAn example which exclude only events with a field `@type` of value `GatewayEvent` :\n```json\n{\n \"exclude\": [\n { \"@type\": \"GatewayEvent\" }\n ],\n \"include\": []\n}\n```\n\nThe next field is the **Projection**. This field is a json when you can list the fields to keep for each event.\n\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nWith this example, only `@type`, `@timestamp` and `@id` will be send to ES.\n\n### Debug your configuration\n\n#### Missing user rights on Elasticsearch\n\nWhen creating an exporter, Otoroshi try to join the index route of the elasticsearch instance. If you have a specific management access rights on Elasticsearch, you have two possiblities :\n\n- set a full access to the user used in Otoroshi for write in Elasticsearch\n- set the version of Elasticsearch inside the `Version` field of your exporter.\n\n#### None event appear in your Elasticsearch\n\nWhen creating an exporter, Otoroshi try to push the index template on Elasticsearch. If the post failed, Otoroshi will fail for each push of events and your database will keep empty. \n\nTo fix this problem, you can try to send the index template with the `Manually apply index template` button in your exporter." - }, - { - "name": "import-export-otoroshi-datastore.md", - "id": "/how-to-s/import-export-otoroshi-datastore.md", - "url": "/how-to-s/import-export-otoroshi-datastore.html", - "title": "Import and export Otoroshi datastore", - "content": "# Import and export Otoroshi datastore\n\n### Start Otoroshi with an initial datastore\n\nLet's start by downloading the latest Otoroshi\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nBy default, Otoroshi starts with domain `oto.tools` that targets `127.0.0.1` Now you are almost ready to run Otoroshi for the first time, we want run it with an initial data.\n\nTo do that, you need to add the **otoroshi.importFrom** setting to the Otoroshi configuration (of `$APP_IMPORT_FROM` env). It can be a file path or a URL. The content of the initial datastore can look something like the following.\n\n```json\n{\n \"label\": \"Otoroshi initial datastore\",\n \"admins\": [],\n \"simpleAdmins\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"username\": \"admin@otoroshi.io\",\n \"password\": \"$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.\",\n \"label\": \"Otoroshi Admin\",\n \"createdAt\": 1634651307724,\n \"type\": \"SIMPLE\",\n \"metadata\": {},\n \"tags\": [],\n \"rights\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ]\n }\n ],\n \"serviceGroups\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"admin-api-group\",\n \"name\": \"Otoroshi Admin Api group\",\n \"description\": \"No description\",\n \"tags\": [],\n \"metadata\": {}\n },\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"default\",\n \"name\": \"default-group\",\n \"description\": \"The default service group\",\n \"tags\": [],\n \"metadata\": {}\n }\n ],\n \"apiKeys\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"clientId\": \"admin-api-apikey-id\",\n \"clientSecret\": \"admin-api-apikey-secret\",\n \"clientName\": \"Otoroshi Backoffice ApiKey\",\n \"description\": \"The apikey use by the Otoroshi UI\",\n \"authorizedGroup\": \"admin-api-group\",\n \"authorizedEntities\": [\n \"group_admin-api-group\"\n ],\n \"enabled\": true,\n \"readOnly\": false,\n \"allowClientIdOnly\": false,\n \"throttlingQuota\": 10000,\n \"dailyQuota\": 10000000,\n \"monthlyQuota\": 10000000,\n \"constrainedServicesOnly\": false,\n \"restrictions\": {\n \"enabled\": false,\n \"allowLast\": true,\n \"allowed\": [],\n \"forbidden\": [],\n \"notFound\": []\n },\n \"rotation\": {\n \"enabled\": false,\n \"rotationEvery\": 744,\n \"gracePeriod\": 168,\n \"nextSecret\": null\n },\n \"validUntil\": null,\n \"tags\": [],\n \"metadata\": {}\n }\n ],\n \"serviceDescriptors\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"admin-api-service\",\n \"groupId\": \"admin-api-group\",\n \"groups\": [\n \"admin-api-group\"\n ],\n \"name\": \"otoroshi-admin-api\",\n \"description\": \"\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"otoroshi-api\",\n \"targetsLoadBalancing\": {\n \"type\": \"RoundRobin\"\n },\n \"targets\": [\n {\n \"host\": \"127.0.0.1:8080\",\n \"scheme\": \"http\",\n \"weight\": 1,\n \"mtlsConfig\": {\n \"certs\": [],\n \"trustedCerts\": [],\n \"mtls\": false,\n \"loose\": false,\n \"trustAll\": false\n },\n \"tags\": [],\n \"metadata\": {},\n \"protocol\": \"HTTP/1.1\",\n \"predicate\": {\n \"type\": \"AlwaysMatch\"\n },\n \"ipAddress\": null\n }\n ],\n \"root\": \"/\",\n \"matchingRoot\": null,\n \"stripPath\": true,\n \"localHost\": \"127.0.0.1:8080\",\n \"localScheme\": \"http\",\n \"redirectToLocal\": false,\n \"enabled\": true,\n \"userFacing\": false,\n \"privateApp\": false,\n \"forceHttps\": false,\n \"logAnalyticsOnServer\": false,\n \"useAkkaHttpClient\": true,\n \"useNewWSClient\": false,\n \"tcpUdpTunneling\": false,\n \"detectApiKeySooner\": false,\n \"maintenanceMode\": false,\n \"buildMode\": false,\n \"strictlyPrivate\": false,\n \"enforceSecureCommunication\": true,\n \"sendInfoToken\": true,\n \"sendStateChallenge\": true,\n \"sendOtoroshiHeadersBack\": true,\n \"readOnly\": false,\n \"xForwardedHeaders\": false,\n \"overrideHost\": true,\n \"allowHttp10\": true,\n \"letsEncrypt\": false,\n \"secComHeaders\": {\n \"claimRequestName\": null,\n \"stateRequestName\": null,\n \"stateResponseName\": null\n },\n \"secComTtl\": 30000,\n \"secComVersion\": 1,\n \"secComInfoTokenVersion\": \"Legacy\",\n \"secComExcludedPatterns\": [],\n \"securityExcludedPatterns\": [],\n \"publicPatterns\": [\n \"/health\",\n \"/metrics\"\n ],\n \"privatePatterns\": [],\n \"additionalHeaders\": {\n \"Host\": \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"additionalHeadersOut\": {},\n \"missingOnlyHeadersIn\": {},\n \"missingOnlyHeadersOut\": {},\n \"removeHeadersIn\": [],\n \"removeHeadersOut\": [],\n \"headersVerification\": {},\n \"matchingHeaders\": {},\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"api\": {\n \"exposeApi\": false\n },\n \"healthCheck\": {\n \"enabled\": false,\n \"url\": \"/\"\n },\n \"clientConfig\": {\n \"useCircuitBreaker\": true,\n \"retries\": 1,\n \"maxErrors\": 20,\n \"retryInitialDelay\": 50,\n \"backoffFactor\": 2,\n \"callTimeout\": 30000,\n \"callAndStreamTimeout\": 120000,\n \"connectionTimeout\": 10000,\n \"idleTimeout\": 60000,\n \"globalTimeout\": 30000,\n \"sampleInterval\": 2000,\n \"proxy\": {},\n \"customTimeouts\": [],\n \"cacheConnectionSettings\": {\n \"enabled\": false,\n \"queueSize\": 2048\n }\n },\n \"canary\": {\n \"enabled\": false,\n \"traffic\": 0.2,\n \"targets\": [],\n \"root\": \"/\"\n },\n \"gzip\": {\n \"enabled\": false,\n \"excludedPatterns\": [],\n \"whiteList\": [\n \"text/*\",\n \"application/javascript\",\n \"application/json\"\n ],\n \"blackList\": [],\n \"bufferSize\": 8192,\n \"chunkedThreshold\": 102400,\n \"compressionLevel\": 5\n },\n \"metadata\": {},\n \"tags\": [],\n \"chaosConfig\": {\n \"enabled\": false,\n \"largeRequestFaultConfig\": null,\n \"largeResponseFaultConfig\": null,\n \"latencyInjectionFaultConfig\": null,\n \"badResponsesFaultConfig\": null\n },\n \"jwtVerifier\": {\n \"type\": \"ref\",\n \"ids\": [],\n \"id\": null,\n \"enabled\": false,\n \"excludedPatterns\": []\n },\n \"secComSettings\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComUseSameAlgo\": true,\n \"secComAlgoChallengeOtoToBack\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComAlgoChallengeBackToOto\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComAlgoInfoToken\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"cors\": {\n \"enabled\": false,\n \"allowOrigin\": \"*\",\n \"exposeHeaders\": [],\n \"allowHeaders\": [],\n \"allowMethods\": [],\n \"excludedPatterns\": [],\n \"maxAge\": null,\n \"allowCredentials\": true\n },\n \"redirection\": {\n \"enabled\": false,\n \"code\": 303,\n \"to\": \"https://www.otoroshi.io\"\n },\n \"authConfigRef\": null,\n \"clientValidatorRef\": null,\n \"transformerRef\": null,\n \"transformerRefs\": [],\n \"transformerConfig\": {},\n \"apiKeyConstraints\": {\n \"basicAuth\": {\n \"enabled\": true,\n \"headerName\": null,\n \"queryName\": null\n },\n \"customHeadersAuth\": {\n \"enabled\": true,\n \"clientIdHeaderName\": null,\n \"clientSecretHeaderName\": null\n },\n \"clientIdAuth\": {\n \"enabled\": true,\n \"headerName\": null,\n \"queryName\": null\n },\n \"jwtAuth\": {\n \"enabled\": true,\n \"secretSigned\": true,\n \"keyPairSigned\": true,\n \"includeRequestAttributes\": false,\n \"maxJwtLifespanSecs\": null,\n \"headerName\": null,\n \"queryName\": null,\n \"cookieName\": null\n },\n \"routing\": {\n \"noneTagIn\": [],\n \"oneTagIn\": [],\n \"allTagsIn\": [],\n \"noneMetaIn\": {},\n \"oneMetaIn\": {},\n \"allMetaIn\": {},\n \"noneMetaKeysIn\": [],\n \"oneMetaKeyIn\": [],\n \"allMetaKeysIn\": []\n }\n },\n \"restrictions\": {\n \"enabled\": false,\n \"allowLast\": true,\n \"allowed\": [],\n \"forbidden\": [],\n \"notFound\": []\n },\n \"accessValidator\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excludedPatterns\": []\n },\n \"preRouting\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excludedPatterns\": []\n },\n \"plugins\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excluded\": []\n },\n \"hosts\": [\n \"otoroshi-api.oto.tools\"\n ],\n \"paths\": [],\n \"handleLegacyDomain\": true,\n \"issueCert\": false,\n \"issueCertCA\": null\n }\n ],\n \"errorTemplates\": [],\n \"jwtVerifiers\": [],\n \"authConfigs\": [],\n \"certificates\": [],\n \"clientValidators\": [],\n \"scripts\": [],\n \"tcpServices\": [],\n \"dataExporters\": [],\n \"tenants\": [\n {\n \"id\": \"default\",\n \"name\": \"Default organization\",\n \"description\": \"The default organization\",\n \"metadata\": {},\n \"tags\": []\n }\n ],\n \"teams\": [\n {\n \"id\": \"default\",\n \"tenant\": \"default\",\n \"name\": \"Default Team\",\n \"description\": \"The default Team of the default organization\",\n \"metadata\": {},\n \"tags\": []\n }\n ]\n}\n```\n\nRun an Otoroshi with the previous file as parameter.\n\n```sh\njava \\\n -Dotoroshi.adminPassword=password \\\n -Dotoroshi.importFrom=./initial-state.json \\\n -jar otoroshi.jar \n```\n\nThis should display\n\n```sh\n...\n[info] otoroshi-env - Importing from: ./initial-state.json\n[info] otoroshi-env - Successful import !\n...\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n...\n```\n\n> Warning : when you using Otoroshi with a datastore different from file or in-memory, Otoroshi will not reload the initialization script. If you expected, you have to manually clean your store.\n\n### Export the current datastore via the danger zone\n\nWhen Otoroshi is running, you can backup the global configuration store from the UI. Navigate to your instance (in our case @link:[http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) { open=new }) and scroll to the bottom page. \n\nClick on `Full export` button to download the full global configuration.\n\n### Import a datastore from file via the danger zone\n\nWhen Otoroshi is running, you can recover a global configuration from the UI. Navigate to your instance (in our case @link:[http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) { open=new }) and scroll to the bottom of the page. \n\nClick on `Recover from a full export file` button to apply all configurations from a file.\n\n### Export the current datastore with the Admin API\n\nOtoroshi exposes his own Admin API to manage Otoroshi resources. To call this api, you need to have an api key with the rights on `Otoroshi Admin Api group`. This group includes the `Otoroshi-admin-api` service that you can found on the services page. \n\nBy default, and with our initial configuration, Otoroshi has already created an api key named `Otoroshi Backoffice ApiKey`. You can verify the rights of an api key on its page by checking the `Authorized On` field (you should find the `Otoroshi Admin Api group` inside).\n\nThe default api key id and secret are `admin-api-apikey-id` and `admin-api-apikey-secret`.\n\nRun the next command with these values.\n\n```sh\ncurl \\\n -H 'Content-Type: application/json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json'\n```\n\nWhen calling the `/api/otoroshi.json`, the return should be the current datastore including the service descriptors, the api keys, all others resources like certificates and authentification modules, and the the global config (representing the form of the danger zone).\n\n### Import the current datastore with the Admin API\n\nAs the same way of previous section, you can erase the current datastore with a POST request. The route is the same : `/api/otoroshi.json`.\n\n```sh\ncurl \\\n -X POST \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"label\" : \"Otoroshi export\",\n \"dateRaw\" : 1634714811217,\n \"date\" : \"2021-10-20 09:26:51\",\n \"stats\" : {\n \"calls\" : 4,\n \"dataIn\" : 0,\n \"dataOut\" : 97991\n },\n \"config\" : {\n \"tags\" : [ ],\n \"letsEncryptSettings\" : {\n \"enabled\" : false,\n \"server\" : \"acme://letsencrypt.org/staging\",\n \"emails\" : [ ],\n \"contacts\" : [ ],\n \"publicKey\" : \"\",\n \"privateKey\" : \"\"\n },\n \"lines\" : [ \"prod\" ],\n \"maintenanceMode\" : false,\n \"enableEmbeddedMetrics\" : true,\n \"streamEntityOnly\" : true,\n \"autoLinkToDefaultGroup\" : true,\n \"limitConcurrentRequests\" : false,\n \"maxConcurrentRequests\" : 1000,\n \"maxHttp10ResponseSize\" : 4194304,\n \"useCircuitBreakers\" : true,\n \"apiReadOnly\" : false,\n \"u2fLoginOnly\" : false,\n \"trustXForwarded\" : true,\n \"ipFiltering\" : {\n \"whitelist\" : [ ],\n \"blacklist\" : [ ]\n },\n \"throttlingQuota\" : 10000000,\n \"perIpThrottlingQuota\" : 10000000,\n \"analyticsWebhooks\" : [ ],\n \"alertsWebhooks\" : [ ],\n \"elasticWritesConfigs\" : [ ],\n \"elasticReadsConfig\" : null,\n \"alertsEmails\" : [ ],\n \"logAnalyticsOnServer\" : false,\n \"useAkkaHttpClient\" : false,\n \"endlessIpAddresses\" : [ ],\n \"statsdConfig\" : null,\n \"kafkaConfig\" : {\n \"servers\" : [ ],\n \"keyPass\" : null,\n \"keystore\" : null,\n \"truststore\" : null,\n \"topic\" : \"otoroshi-events\",\n \"mtlsConfig\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n },\n \"backOfficeAuthRef\" : null,\n \"mailerSettings\" : {\n \"type\" : \"none\"\n },\n \"cleverSettings\" : null,\n \"maxWebhookSize\" : 100,\n \"middleFingers\" : false,\n \"maxLogsSize\" : 10000,\n \"otoroshiId\" : \"83539cbca-76ee-4abc-ad31-a4794e873848\",\n \"snowMonkeyConfig\" : {\n \"enabled\" : false,\n \"outageStrategy\" : \"OneServicePerGroup\",\n \"includeUserFacingDescriptors\" : false,\n \"dryRun\" : false,\n \"timesPerDay\" : 1,\n \"startTime\" : \"09:00:00.000\",\n \"stopTime\" : \"23:59:59.000\",\n \"outageDurationFrom\" : 600000,\n \"outageDurationTo\" : 3600000,\n \"targetGroups\" : [ ],\n \"chaosConfig\" : {\n \"enabled\" : true,\n \"largeRequestFaultConfig\" : null,\n \"largeResponseFaultConfig\" : null,\n \"latencyInjectionFaultConfig\" : {\n \"ratio\" : 0.2,\n \"from\" : 500,\n \"to\" : 5000\n },\n \"badResponsesFaultConfig\" : {\n \"ratio\" : 0.2,\n \"responses\" : [ {\n \"status\" : 502,\n \"body\" : \"{\\\"error\\\":\\\"Nihonzaru everywhere ...\\\"}\",\n \"headers\" : {\n \"Content-Type\" : \"application/json\"\n }\n } ]\n }\n }\n },\n \"scripts\" : {\n \"enabled\" : false,\n \"transformersRefs\" : [ ],\n \"transformersConfig\" : { },\n \"validatorRefs\" : [ ],\n \"validatorConfig\" : { },\n \"preRouteRefs\" : [ ],\n \"preRouteConfig\" : { },\n \"sinkRefs\" : [ ],\n \"sinkConfig\" : { },\n \"jobRefs\" : [ ],\n \"jobConfig\" : { }\n },\n \"geolocationSettings\" : {\n \"type\" : \"none\"\n },\n \"userAgentSettings\" : {\n \"enabled\" : false\n },\n \"autoCert\" : {\n \"enabled\" : false,\n \"replyNicely\" : false,\n \"caRef\" : null,\n \"allowed\" : [ ],\n \"notAllowed\" : [ ]\n },\n \"tlsSettings\" : {\n \"defaultDomain\" : null,\n \"randomIfNotFound\" : false,\n \"includeJdkCaServer\" : true,\n \"includeJdkCaClient\" : true,\n \"trustedCAsServer\" : [ ]\n },\n \"plugins\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excluded\" : [ ]\n },\n \"metadata\" : { }\n },\n \"admins\" : [ ],\n \"simpleAdmins\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"username\" : \"admin@otoroshi.io\",\n \"password\" : \"$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.\",\n \"label\" : \"Otoroshi Admin\",\n \"createdAt\" : 1634651307724,\n \"type\" : \"SIMPLE\",\n \"metadata\" : { },\n \"tags\" : [ ],\n \"rights\" : [ {\n \"tenant\" : \"*:rw\",\n \"teams\" : [ \"*:rw\" ]\n } ]\n } ],\n \"serviceGroups\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"admin-api-group\",\n \"name\" : \"Otoroshi Admin Api group\",\n \"description\" : \"No description\",\n \"tags\" : [ ],\n \"metadata\" : { }\n }, {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"default\",\n \"name\" : \"default-group\",\n \"description\" : \"The default service group\",\n \"tags\" : [ ],\n \"metadata\" : { }\n } ],\n \"apiKeys\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"clientId\" : \"admin-api-apikey-id\",\n \"clientSecret\" : \"admin-api-apikey-secret\",\n \"clientName\" : \"Otoroshi Backoffice ApiKey\",\n \"description\" : \"The apikey use by the Otoroshi UI\",\n \"authorizedGroup\" : \"admin-api-group\",\n \"authorizedEntities\" : [ \"group_admin-api-group\" ],\n \"enabled\" : true,\n \"readOnly\" : false,\n \"allowClientIdOnly\" : false,\n \"throttlingQuota\" : 10000,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"constrainedServicesOnly\" : false,\n \"restrictions\" : {\n \"enabled\" : false,\n \"allowLast\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"notFound\" : [ ]\n },\n \"rotation\" : {\n \"enabled\" : false,\n \"rotationEvery\" : 744,\n \"gracePeriod\" : 168,\n \"nextSecret\" : null\n },\n \"validUntil\" : null,\n \"tags\" : [ ],\n \"metadata\" : { }\n } ],\n \"serviceDescriptors\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"admin-api-service\",\n \"groupId\" : \"admin-api-group\",\n \"groups\" : [ \"admin-api-group\" ],\n \"name\" : \"otoroshi-admin-api\",\n \"description\" : \"\",\n \"env\" : \"prod\",\n \"domain\" : \"oto.tools\",\n \"subdomain\" : \"otoroshi-api\",\n \"targetsLoadBalancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"targets\" : [ {\n \"host\" : \"127.0.0.1:8080\",\n \"scheme\" : \"http\",\n \"weight\" : 1,\n \"mtlsConfig\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n },\n \"tags\" : [ ],\n \"metadata\" : { },\n \"protocol\" : \"HTTP/1.1\",\n \"predicate\" : {\n \"type\" : \"AlwaysMatch\"\n },\n \"ipAddress\" : null\n } ],\n \"root\" : \"/\",\n \"matchingRoot\" : null,\n \"stripPath\" : true,\n \"localHost\" : \"127.0.0.1:8080\",\n \"localScheme\" : \"http\",\n \"redirectToLocal\" : false,\n \"enabled\" : true,\n \"userFacing\" : false,\n \"privateApp\" : false,\n \"forceHttps\" : false,\n \"logAnalyticsOnServer\" : false,\n \"useAkkaHttpClient\" : true,\n \"useNewWSClient\" : false,\n \"tcpUdpTunneling\" : false,\n \"detectApiKeySooner\" : false,\n \"maintenanceMode\" : false,\n \"buildMode\" : false,\n \"strictlyPrivate\" : false,\n \"enforceSecureCommunication\" : true,\n \"sendInfoToken\" : true,\n \"sendStateChallenge\" : true,\n \"sendOtoroshiHeadersBack\" : true,\n \"readOnly\" : false,\n \"xForwardedHeaders\" : false,\n \"overrideHost\" : true,\n \"allowHttp10\" : true,\n \"letsEncrypt\" : false,\n \"secComHeaders\" : {\n \"claimRequestName\" : null,\n \"stateRequestName\" : null,\n \"stateResponseName\" : null\n },\n \"secComTtl\" : 30000,\n \"secComVersion\" : 1,\n \"secComInfoTokenVersion\" : \"Legacy\",\n \"secComExcludedPatterns\" : [ ],\n \"securityExcludedPatterns\" : [ ],\n \"publicPatterns\" : [ \"/health\", \"/metrics\" ],\n \"privatePatterns\" : [ ],\n \"additionalHeaders\" : {\n \"Host\" : \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"additionalHeadersOut\" : { },\n \"missingOnlyHeadersIn\" : { },\n \"missingOnlyHeadersOut\" : { },\n \"removeHeadersIn\" : [ ],\n \"removeHeadersOut\" : [ ],\n \"headersVerification\" : { },\n \"matchingHeaders\" : { },\n \"ipFiltering\" : {\n \"whitelist\" : [ ],\n \"blacklist\" : [ ]\n },\n \"api\" : {\n \"exposeApi\" : false\n },\n \"healthCheck\" : {\n \"enabled\" : false,\n \"url\" : \"/\"\n },\n \"clientConfig\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n },\n \"canary\" : {\n \"enabled\" : false,\n \"traffic\" : 0.2,\n \"targets\" : [ ],\n \"root\" : \"/\"\n },\n \"gzip\" : {\n \"enabled\" : false,\n \"excludedPatterns\" : [ ],\n \"whiteList\" : [ \"text/*\", \"application/javascript\", \"application/json\" ],\n \"blackList\" : [ ],\n \"bufferSize\" : 8192,\n \"chunkedThreshold\" : 102400,\n \"compressionLevel\" : 5\n },\n \"metadata\" : { },\n \"tags\" : [ ],\n \"chaosConfig\" : {\n \"enabled\" : false,\n \"largeRequestFaultConfig\" : null,\n \"largeResponseFaultConfig\" : null,\n \"latencyInjectionFaultConfig\" : null,\n \"badResponsesFaultConfig\" : null\n },\n \"jwtVerifier\" : {\n \"type\" : \"ref\",\n \"ids\" : [ ],\n \"id\" : null,\n \"enabled\" : false,\n \"excludedPatterns\" : [ ]\n },\n \"secComSettings\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComUseSameAlgo\" : true,\n \"secComAlgoChallengeOtoToBack\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComAlgoChallengeBackToOto\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComAlgoInfoToken\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"cors\" : {\n \"enabled\" : false,\n \"allowOrigin\" : \"*\",\n \"exposeHeaders\" : [ ],\n \"allowHeaders\" : [ ],\n \"allowMethods\" : [ ],\n \"excludedPatterns\" : [ ],\n \"maxAge\" : null,\n \"allowCredentials\" : true\n },\n \"redirection\" : {\n \"enabled\" : false,\n \"code\" : 303,\n \"to\" : \"https://www.otoroshi.io\"\n },\n \"authConfigRef\" : null,\n \"clientValidatorRef\" : null,\n \"transformerRef\" : null,\n \"transformerRefs\" : [ ],\n \"transformerConfig\" : { },\n \"apiKeyConstraints\" : {\n \"basicAuth\" : {\n \"enabled\" : true,\n \"headerName\" : null,\n \"queryName\" : null\n },\n \"customHeadersAuth\" : {\n \"enabled\" : true,\n \"clientIdHeaderName\" : null,\n \"clientSecretHeaderName\" : null\n },\n \"clientIdAuth\" : {\n \"enabled\" : true,\n \"headerName\" : null,\n \"queryName\" : null\n },\n \"jwtAuth\" : {\n \"enabled\" : true,\n \"secretSigned\" : true,\n \"keyPairSigned\" : true,\n \"includeRequestAttributes\" : false,\n \"maxJwtLifespanSecs\" : null,\n \"headerName\" : null,\n \"queryName\" : null,\n \"cookieName\" : null\n },\n \"routing\" : {\n \"noneTagIn\" : [ ],\n \"oneTagIn\" : [ ],\n \"allTagsIn\" : [ ],\n \"noneMetaIn\" : { },\n \"oneMetaIn\" : { },\n \"allMetaIn\" : { },\n \"noneMetaKeysIn\" : [ ],\n \"oneMetaKeyIn\" : [ ],\n \"allMetaKeysIn\" : [ ]\n }\n },\n \"restrictions\" : {\n \"enabled\" : false,\n \"allowLast\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"notFound\" : [ ]\n },\n \"accessValidator\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excludedPatterns\" : [ ]\n },\n \"preRouting\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excludedPatterns\" : [ ]\n },\n \"plugins\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excluded\" : [ ]\n },\n \"hosts\" : [ \"otoroshi-api.oto.tools\" ],\n \"paths\" : [ ],\n \"handleLegacyDomain\" : true,\n \"issueCert\" : false,\n \"issueCertCA\" : null\n } ],\n \"errorTemplates\" : [ ],\n \"jwtVerifiers\" : [ ],\n \"authConfigs\" : [ ],\n \"certificates\" : [],\n \"clientValidators\" : [ ],\n \"scripts\" : [ ],\n \"tcpServices\" : [ ],\n \"dataExporters\" : [ ],\n \"tenants\" : [ {\n \"id\" : \"default\",\n \"name\" : \"Default organization\",\n \"description\" : \"The default organization\",\n \"metadata\" : { },\n \"tags\" : [ ]\n } ],\n \"teams\" : [ {\n \"id\" : \"default\",\n \"tenant\" : \"default\",\n \"name\" : \"Default Team\",\n \"description\" : \"The default Team of the default organization\",\n \"metadata\" : { },\n \"tags\" : [ ]\n } ]\n }' \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \n```\n\nThis should output :\n\n```json\n{ \"done\":true }\n```\n\n> Note : be very carefully with this POST command. If you send a wrong JSON, you risk breaking your instance.\n\nThe second way is to send the same configuration but from a file. You can pass two kind of file : a `json` file or a `ndjson` file. Both files are available as export methods on the danger zone.\n\n```sh\n# the curl is run from a folder containing the initial-state.json file \ncurl -X POST \\\n -H \"Content-Type: application/json\" \\\n -d @./initial-state.json \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nThis should output :\n\n```json\n{ \"done\":true }\n```\n\n> Note: To send a ndjson file, you have to set the Content-Type header at `application/x-ndjson`" - }, - { - "name": "index.md", - "id": "/how-to-s/index.md", - "url": "/how-to-s/index.html", - "title": "How to's", - "content": "# How to's\n\nin this section, we will explain some mainstream Otoroshi usage scenario's \n\n* @ref:[End-to-end mTLS](./end-to-end-mtls.md)\n* @ref:[Send alerts by emails](./export-alerts-using-mailgun.md)\n* @ref:[Export events to Elasticsearch](./export-events-to-elastic.md)\n* @ref:[Import/export Otoroshi datastore](./import-export-otoroshi-datastore.md)\n* @ref:[Secure an app with Auth0](./secure-app-with-auth0.md)\n* @ref:[Secure an app with Keycloak](./secure-app-with-keycloak.md)\n* @ref:[Secure an app with LDAP](./secure-app-with-ldap.md)\n* @ref:[Secure an api with apikeys](./secure-with-apikey.md)\n* @ref:[Secure an app with OAuth1](./secure-with-oauth1-client.md)\n* @ref:[Secure an api with OAuth2 client_credentials flow](./secure-with-oauth2-client-credentials.md)\n* @ref:[Setup an Otoroshi cluster](./setup-otoroshi-cluster.md)\n* @ref:[TLS termination using Let's Encrypt](./tls-using-lets-encrypt.md)\n* @ref:[Secure an app with jwt verifiers](./secure-an-app-with-jwt-verifiers.md)\n* @ref:[Secure the communication between a backend app and Otoroshi](./secure-the-communication-between-a-backend-app-and-otoroshi.md)\n* @ref:[TLS termination using your own certificates](./tls-termination-using-own-certificates.md)\n* @ref:[The resources loader](./resources-loader.md)\n* @ref:[Log levels customization](./custom-log-levels.md)\n* @ref:[Initial state customization](./custom-initial-state.md)\n\n@@@ index\n\n* [End-to-end mTLS](./end-to-end-mtls.md)\n* [Send alerts by emails](./export-alerts-using-mailgun.md)\n* [Export events to Elasticsearch](./export-events-to-elastic.md)\n* [Import/export Otoroshi datastore](./import-export-otoroshi-datastore.md)\n* [Secure an app with Auth0](./secure-app-with-auth0.md)\n* [Secure an app with Keycloak](./secure-app-with-keycloak.md)\n* [Secure an app with LDAP](./secure-app-with-ldap.md)\n* [Secure an api with apikeys](./secure-with-apikey.md)\n* [Secure an app with OAuth1](./secure-with-oauth1-client.md)\n* [Secure an api with OAuth2 client_credentials flow](./secure-with-oauth2-client-credentials.md)\n* [Setup an Otoroshi cluster](./setup-otoroshi-cluster.md)\n* [TLS termination using Let's Encrypt](./tls-using-lets-encrypt.md)\n* [Secure an app with jwt verifiers](./secure-an-app-with-jwt-verifiers.md)\n* [Secure the communication between a backend app and Otoroshi](./secure-the-communication-between-a-backend-app-and-otoroshi.md)\n* [TLS termination using your own certificates](./tls-termination-using-own-certificates.md)\n* [The resources loader](./resources-loader.md)\n* [Log levels customization](./custom-log-levels.md)\n* [Initial state customization](./custom-initial-state.md)\n\n@@@" - }, - { - "name": "resources-loader.md", - "id": "/how-to-s/resources-loader.md", - "url": "/how-to-s/resources-loader.html", - "title": "The resources loader", - "content": "# The resources loader\n\nThe resources loader is a tool to create an Otoroshi resource from a raw content. This content can be found on each Otoroshi resources pages (services descriptors, apikeys, certificates, etc ...). To get the content of a resource as file, you can use the two export buttons, one to export as JSON format and the other as YAML format.\n\nOnce exported, the content of the resource can be import with the resource loader. You can import single or multiples resources on one time, as JSON and YAML format.\n\nThe resource loader is available on this route [`bo/dashboard/resources-loader`](http://otoroshi.oto.tools:8080/bo/dashboard/resources-loader).\n\nOn this page, you can paste the content of your resources and click on **Load resources**.\n\nFor each detected resource, the loader will display :\n\n* a resource name corresponding to the field `name` \n* a resource type corresponding to the type of created resource (ServiceDescriptor, ApiKey, Certificate, etc)\n* a toggle to choose if you want to include the element for the creation step\n* the updated status by the creation process\n\nOnce you have selected the resources to create, you can **Import selected resources**.\n\nOnce generated, all status will be updated. If all is working, the status will be equals to done.\n\nIf you want to get back to the initial page, you can use the **restart** button." - }, - { - "name": "secure-an-app-with-jwt-verifiers.md", - "id": "/how-to-s/secure-an-app-with-jwt-verifiers.md", - "url": "/how-to-s/secure-an-app-with-jwt-verifiers.html", - "title": "Secure an api with jwt verifiers", - "content": "# Secure an api with jwt verifiers\n\nA Jwt verifier is the guard which check the signature of tokens present in incoming requests on a service. It can be a simple verifier, a tokens generator, or extend to be a verifier and a tokens generator.\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Your first jwt verifier : a verifier of tokens\n\nLet's start navigating the @link:[page of verifier creation](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers/add) { open=new }. By default, the type of jwt verifier is a **Verify JWT token**.\n\nCreate the following verifier : \n\n* Set `simple-jwt-verifier` as `Name`\n* Set `My simple jwt verifier` as `Description`\n* We expect in entry a token in a specific header. Set `Authorization` as `Header name`\n* Select `Hmac + SHA` as `Algo` (for this example, we expect tokens with a symetric signature)\n* Set `otoroshi` as `Hmac secret`\n* Remove the default field in `Verify token fields` array\n* Create your verifier when clicking on `Create and stay on this Jwt verifier` button.\n\nOnce created, navigate to the simple service (created in @ref:[Before you start](#before-you-start) section) and jump to the `JWT tokens verification` section.\n\nIn the verifiers list, choose the `simple-jwt-verifier` and `enabled` the section.\n\nSave your service and try to call the service.\n```sh\ncurl -X GET 'http://myservice.oto.tools:8080/' --include\n```\n\nThis should output : \n```json\n{\n \"Otoroshi-Error\": \"error.expected.token.not.found\"\n}\n```\n\nA simple way to generate a token is to use @link:[jwt.io](http://jwt.io) { open=new }. Once navigate, define `HS512` as `alg` in header section, and insert `otoroshi` as verify signature secret. \n\nOnce created, copy-paste the token from jwt.io to the Authorization header and call our service.\n\n```sh\n# replace xxxx by the generated token\ncurl -X GET \\\n -H \"Authorization: xxxx\" \\\n 'http://myservice.oto.tools:8080'\n```\n\nThis should output a json with `authorization` in headers field. His value is exactly the same as the passed token.\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.otoroshi.io\",\n \"authorization\": \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.ipDFgkww51mSaSg_199BMRj4gK20LGz_czozu3u8rCFFO1X20MwcabSqEzUc0q4qQ4rjTxjoR4HeUDVcw8BxoQ\",\n ...\n }\n}\n```\n\n### Verify and generate a new token\n\nAn other feature is to verify the entry token and generate a new token, with a different signature and news claims. \n\nLet's start by extending the @link:[previous verifier](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers) { open=new }.\n\n1. Jump to the `Verif Strategy` field and select `Verify and re-sign JWT token`. \n2. Edit the name with `jwt-verify-and-resign`\n3. Remove the default field in `Verify token fields` array\n4. Change the second `Hmac secret` in `Re-sign settings` section with `otoroshi-internal-secret`\n5. Save your verifier.\n\n> Note : the name of the verifier doesn't impact the identifier. So you can save the changes of your verifier without modifying the identifier used in your call. \n\n```sh\n# replace xxxx by the generated token\ncurl -X GET \\\n -H \"Authorization: xxxx\" \\\n 'http://myservice.oto.tools:8080'\n```\n\nThis should output a json with `authorization` in headers field. This time, the value are different and you can check his signature on @link:[jwt.io](https://jwt.io) { open=new } (the expected secret of the generated token is **otoroshi-internal-secret**)\n\n\n\n### Verify, transform and generate a new token\n\nThe most advanced verifier is able to do the same as the previous ones, with the ability to configure the token generation (claims, output header name).\n\nLet's start by extending the @link:[previous verifier](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers) { open=new }.\n\n1. Jump to the `Verif Strategy` field and select `Verify, transform and re-sign JWT token`. \n\n2. Edit the name with `jwt-verify-transform-and-resign`\n3. Remove the default field in `Verify token fields` array\n4. Change the second `Hmac secret` in `Re-sign settings` section with `otoroshi-internal-secret`\n5. Set `Internal-Authorization` as `Header name`\n6. Set `key` on first field of `Rename token fields` and `from-otoroshi-verifier` on second field\n7. Set `generated-key` and `generated-value` as `Set token fields`\n8. Add `generated_at` and `${date}` as second field of `Set token fields` (Otoroshi supports an @ref:[expression language](../topics/expression-language.md))\n9. Save your verifier and try to call your service again.\n\nThis should output a json with `authorization` in headers field and our generate token in `Internal-Authorization`.\nOnce paste in @link:[jwt.io](https://jwt.io) { open=new }, you should have :\n\n\n\nYou can see, in the payload of your token, the two claims **from-otoroshi-verifier** and **generated-key** added during the generation of the token by the JWT verifier.\n" - }, - { - "name": "secure-app-with-auth0.md", - "id": "/how-to-s/secure-app-with-auth0.md", - "url": "/how-to-s/secure-app-with-auth0.html", - "title": "Secure an app with Auth0", - "content": "# Secure an app with Auth0\n\n### Download Otoroshi\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Configure an Auth0 client\n\nThe first step of this tutorial is to setup an Auth0 application with the information of the instance of our Otoroshi.\n\nNavigate to @link:[https://manage.auth0.com](https://manage.auth0.com) { open=new } (create an account if it's not already done). \n\nLet's create an application when clicking on the **Applications** button on the sidebar. Then click on the **Create application** button on the top right.\n\n1. Choose `Regular Web Applications` as `Application type`\n2. Then set for example `otoroshi-client` as `Name`, and confirm the creation\n3. Jump to the `Settings` tab\n4. Scroll to the `Application URLs` section and add the following url as `Allowed Callback URLs` : `http://otoroshi.oto.tools:8080/backoffice/auth0/callback`\n5. Set `https://otoroshi.oto.tools:8080/` as `Allowed Logout URLs`\n6. Set `https://otoroshi.oto.tools:8080` as `Allowed Web Origins` \n7. Save changes at the bottom of the page.\n\nOnce done, we have a full setup, with a client ID and secret at the top of the page, which authorizes our Otoroshi and redirects the user to the callback url when they log into Auth0.\n\n### Create an Auth0 provider module\n\nLet's back to Otoroshi to create an authentication module with `OAuth2 / OIDC provider` as `type`.\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n1. Click on the cog icon on the top right\n1. Then `Authentication configs` button\n1. And add a new configuration when clicking on the `Add item` button\n2. Select the `OAuth provider` in the type selector field\n3. Then click on `Get from OIDC config` and paste `https://..auth0.com/.well-known/openid-configuration`. Replace the tenant name by the name of your tenant (displayed on the left top of auth0 page), and the region of the tenant (`eu` in my case).\n\nOnce done, set the `Client ID` and the `Client secret` from your Auth0 application. End the configuration with `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Callback URL`.\n\nAt the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs).\n\n### Connect to Otoroshi with Auth0 authentication\n\nTo secure Otoroshi with your Auth0 configuration, we have to register an **Authentication configuration** as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n2. Scroll to the **BackOffice auth. settings**\n3. Select your last Authentication configuration (created in the previous section)\n4. Save the global configuration with the button on the top right\n\n#### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the *Login using third-party* button (or navigate to http://otoroshi.oto.tools:8080)\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the auth0 server login page\n4. Set your account credentials\n5. Good works! You're connected to Otoroshi with an Auth0 module.\n\n### Secure an app with Auth0 authentication\n\nWith the previous configuration, you can secure any of Otoroshi services with it. \n\nThe first step is to apply a little change on the previous configuration. \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs](http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs) { open=new }.\n2. Create a new **Authentication module** configuration with the same values.\n3. Replace the `Callback URL` field to `http://privateapps.oto.tools:8080/privateapps/generic/callback` (we changed this value because the redirection of a connected user by a third-party server is covered by another route by Otoroshi).\n4. Disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n> Note : an Otoroshi service is called **a private app** when it is protected by an Authentication module.\n\nWe can set the Authentication module on the service.\n\n1. Navigate to any created service\n2. Scroll to `Authentication` section\n3. Enable `Enforce user authentication`\n4. Select your Authentication config inside the list\n5. Enable `Strict mode`\n6. Don't forget to save your configuration.\n7. Now you can try to call your defined service and see the Auth0 login page appears.\n\n\n" - }, - { - "name": "secure-app-with-keycloak.md", - "id": "/how-to-s/secure-app-with-keycloak.md", - "url": "/how-to-s/secure-app-with-keycloak.html", - "title": "Secure an app with Keycloak", - "content": "# Secure an app with Keycloak\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Running a keycloak instance with docker\n\n```sh\ndocker run \\\n -p 8080:8080 \\\n -e KEYCLOAK_USER=admin \\\n -e KEYCLOAK_PASSWORD=admin \\\n --name keycloak-server \\\n --detach jboss/keycloak:15.0.1\n```\n\nThis should download the image of keycloak (if you haven't already it) and display the digest of the created container. This command mapped TCP port 8080 in the container to port 8080 of your laptop and created a server with `admin/admin` as admin credentials.\n\nOnce started, you can open a browser on @link:[http://localhost:8080](http://localhost:8080) { open=new } and click on `Administration Console`. Log to your instance with `admin/admin` as credentials.\n\nThe first step is to create a Keycloak client, an entity that can request Keycloak to authenticate a user. Click on the **clients** button on the sidebar, and then on **Create** button at the top right of the view.\n\nFill the client form with the following values.\n\n* `Client ID`: `keycloak-otoroshi-backoffice`\n* `Client Protocol`: `openid-connect`\n* `Root URL`: `http://otoroshi.oto.tools:8080/`\n\nValidate the creation of the client by clicking on the **Save** button.\n\nThe next step is to change the `Access Type` used by default. Jump to the `Access Type` field and select `confidential`. The confidential configuration force the client application to send at Keycloak a client ID and a client Secret. Scroll to the bottom of the page and save the configuration.\n\nNow scroll to the top of your page. Just at the right of the `Settings` tab, a new tab appeared : the `Credentials` page. Click on this tab, and make sure that `Client Id and Secret` is selected as `Client Authenticator` and copy the generated `Secret` to the next part.\n\n### Create a Keycloak provider module\n\n1. Go ahead, and navigate to http://otoroshi.oto.tools:8080\n1. Click on the cog icon on the top right\n1. Then `Authentication configs` button\n1. And add a new configuration when clicking on the `Add item` button\n2. Select the `OAuth2 / OIDC provider` in the type selector field\n3. Set a basic name and description\n\nA simple way to import a Keycloak client is to give the `URL of the OpenID Connect` Otoroshi. By default, keycloak used the next URL : `http://localhost:8080/auth/realms/master/.well-known/openid-configuration`. \n\nClick on the `Get from OIDC config` button and paste the previous link. Once it's done, scroll to the `URLs` section. All URLs has been fill with the values picked from the JSON object returns by the previous URL.\n\nThe only fields to change are : \n\n* `Client ID`: `keycloak-otoroshi-backoffice`\n* `Client Secret`: Paste the secret from the Credentials Keycloak page. In my case, it's something like `90c9bf0b-2c0c-4eb0-aa02-72195beb9da7`\n* `Callback URL`: `http://otoroshi.oto.tools:8080/backoffice/auth0/callback`\n\nAt the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs). Nothing else to change, just save the configuration.\n\n### Connect to Otoroshi with Keycloak authentication\n\nTo secure Otoroshi with your Keycloak configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n1. Scroll to the **BackOffice auth. settings**\n1. Select your last Authentication configuration (created in the previous section)\n1. Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the **Login using third-party** button (or navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new })\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the keycloak login page\n4. Set `admin/admin` as user and trust the user by clicking on `yes` button.\n5. Good work! You're connected to Otoroshi with an Keycloak module.\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n### Visualize an admin user session or a private user session\n\nEach user, wheter connected user to the Otoroshi UI or at a private Otoroshi app, has an own session. As an administrator of Otoroshi, you can visualize via Otoroshi the list of the connected users and their profile.\n\nLet's start by navigating to the `Admin users sessions` page (just @link:[here](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/admin) or when clicking on the cog, and on the `Admins sessions` button at the bottom of the list).\n\nThis page gives a complete view of the connected admins. For each admin, you have his connection date and his expiration date. You can also check the `Profile` and the `Rights` of the connected users.\n\nIf we check the profile and the rights of the previously logged user (from Keycloak in the previous part) we can retrieve the following information :\n\n```json\n{\n \"sub\": \"4c8cd101-ca28-4611-80b9-efa504ac51fd\",\n \"upn\": \"admin\",\n \"email_verified\": false,\n \"address\": {},\n \"groups\": [\n \"create-realm\",\n \"default-roles-master\",\n \"offline_access\",\n \"admin\",\n \"uma_authorization\"\n ],\n \"preferred_username\": \"admin\"\n}\n```\n\nand his default rights \n\n```sh\n[\n {\n \"tenant\": \"default:rw\",\n \"teams\": [\n \"default:rw\"\n ]\n }\n]\n```\n\nWe haven't create any specific groups in Keycloak or specify rights in Otoroshi for him. In this case, the use received the default Otoroshi rights at his connection. The user can navigate on the default Organization and Teams (which are two resources created by Otoroshi at the boot) and have the full access on its (`r`: Read, `w`: Write, `*`: read/write).\n\nIn the same way, you'll find all users connected to a private Otoroshi app when navigate on the @link:[`Private App View`](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private) or using the cog at the top of the page. \n\n### Configure the Keycloak module to force logged in users to be an Otoroshi admin with full access\n\nGo back to the Keycloak module in `Authentication configs` view. Turn on the `Supers admin only` button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.\n\nOnce connected, click on the cog button, and check that you have access to the full features of Otoroshi (like Admin user sessions). Now, your rights should be : \n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n]\n```\n\n### Merge Id token content on user profile\n\nGo back to the Keycloak module in `Authentication configs` view. Turn on the `Read profile` from token button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.\n\nOnce connected, your profile should be contains all Keycloak id token : \n```json\n{\n \"exp\": 1634286674,\n \"iat\": 1634286614,\n \"auth_time\": 1634286614,\n \"jti\": \"eb368578-e886-4caa-a51b-c1d04973c80e\",\n \"iss\": \"http://localhost:8080/auth/realms/master\",\n \"aud\": [\n \"master-realm\",\n \"account\"\n ],\n \"sub\": \"4c8cd101-ca28-4611-80b9-efa504ac51fd\",\n \"typ\": \"Bearer\",\n \"azp\": \"keycloak-otoroshi-backoffice\",\n \"session_state\": \"e44fe471-aa3b-477d-b792-4f7b4caea220\",\n \"acr\": \"1\",\n \"allowed-origins\": [\n \"http://otoroshi.oto.tools:8080\"\n ],\n \"realm_access\": {\n \"roles\": [\n \"create-realm\",\n \"default-roles-master\",\n \"offline_access\",\n \"admin\",\n \"uma_authorization\"\n ]\n },\n \"resource_access\": {\n \"master-realm\": {\n \"roles\": [\n \"view-identity-providers\",\n \"view-realm\",\n \"manage-identity-providers\",\n \"impersonation\",\n \"create-client\",\n \"manage-users\",\n \"query-realms\",\n \"view-authorization\",\n \"query-clients\",\n \"query-users\",\n \"manage-events\",\n \"manage-realm\",\n \"view-events\",\n \"view-users\",\n \"view-clients\",\n \"manage-authorization\",\n \"manage-clients\",\n \"query-groups\"\n ]\n },\n \"account\": {\n \"roles\": [\n \"manage-account\",\n \"manage-account-links\",\n \"view-profile\"\n ]\n }\n }\n ...\n}\n```\n\n### Manage the Otoroshi user rights from keycloak\n\nOne powerful feature supports by Otoroshi, is to use the Keycloak groups attributes to set a list of rights for a Otoroshi user.\n\nIn the Keycloak module, you have a field, named `Otoroshi rights field name` with `otoroshi_rights` as default value. This field is used by Otoroshi to retrieve information from the Id token groups.\n\nLet's create a group in Keycloak, and set our default Admin user inside.\nIn Keycloak admin console :\n\n1. Navigate to the groups view, using the keycloak sidebar\n2. Create a new group with `my-group` as `Name`\n3. Then, on the `Attributes` tab, create an attribute with `otoroshi_rights` as `Key` and the following json array as `Value`\n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```\n\nWith this configuration, the user have a full access on all Otoroshi resources (my-future-team is not created in Otoroshi but it's not a problem, Otoroshi can handle it and use this rights only when the team will be present)\n\nClick on the **Add** button and **save** the group. The last step is to assign our user to this group. Jump to `Users` view using the sidebar, click on **View all users**, edit the user and his group membership using the `Groups` tab (use **join** button the assign user in `my-group`).\n\nThe next step is to add a mapper in the Keycloak client. By default, Keycloak doesn't expose any users information (like group membership or users attribute). We need to ask to Keycloak to expose the user attribute `otoroshi_rights` set previously on group.\n\nNavigate to the `Keycloak-otoroshi-backoffice` client, and jump to `Mappers` tab. Create a new mapper with the following values: \n\n* Name: `otoroshi_rights`\n* Mapper Type: `User Attribute`\n* User Attribute: `otoroshi_rights`\n* Token Claim Name: `otoroshi_rights`\n* Claim JSON Type: `JSON`\n* Multivalued: `√`\n* Aggregate attribute values: `√`\n\nGo back to the Authentication Keycloak module inside Otoroshi UI, and turn off **Super admins only**. **Save** the configuration.\n\nOnce done, try again the connection to Otoroshi using Keycloak third-party server.\nNow, your rights should be : \n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```\n\n### Secure an app with Keycloak authentication\n\nThe only change to apply on the previous authentication module is on the callback URL. When you want secure a Otoroshi service, and transform it on `Private App`, you need to set the `Callback URL` at `http://privateapps.oto.tools:8080/privateapps/generic/callback`. This configuration will redirect users to the backend service after they have successfully logged in.\n\n1. Go back to the authentication module\n2. Jump to the `Callback URL` field\n3. Paste this value `http://privateapps.oto.tools:8080/privateapps/generic/callback`\n4. Save your configuration\n5. Navigate to `http://myservice.oto.tools:8080`.\n6. You should redirect to the keycloak login page.\n7. Once logged in, you can check the content of the private app session created.\n\nThe rights should be : \n\n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```" - }, - { - "name": "secure-app-with-ldap.md", - "id": "/how-to-s/secure-app-with-ldap.md", - "url": "/how-to-s/secure-app-with-ldap.html", - "title": "Secure an app and/or your Otoroshi UI with LDAP", - "content": "# Secure an app and/or your Otoroshi UI with LDAP\n\n### Before you start\n\n@@include[fetch-and-start.md](../includes/fetch-and-start.md) { #init }\n\n#### Running an simple OpenLDAP server \n\nRun OpenLDAP docker image : \n```sh\ndocker run \\\n -p 389:389 \\\n -p 636:636 \\\n --env LDAP_ORGANISATION=\"Otoroshi company\" \\\n --env LDAP_DOMAIN=\"otoroshi.tools\" \\\n --env LDAP_ADMIN_PASSWORD=\"otoroshi\" \\\n --env LDAP_READONLY_USER=\"false\" \\\n --env LDAP_TLS\"false\" \\\n --env LDAP_TLS_ENFORCE\"false\" \\\n --name my-openldap-container \\\n --detach osixia/openldap:1.5.0\n```\n\nLet's make the first search in our LDAP container :\n\n```sh\ndocker exec my-openldap-container ldapsearch -x -H ldap://localhost -b dc=otoroshi,dc=tools -D \"cn=admin,dc=otoroshi,dc=tools\" -w otoroshi\n```\n\nThis should output :\n```sh\n# extended LDIF\n ...\n# otoroshi.tools\ndn: dc=otoroshi,dc=tools\nobjectClass: top\nobjectClass: dcObject\nobjectClass: organization\no: Otoroshi company\ndc: otoroshi\n\n# search result\nsearch: 2\nresult: 0 Success\n...\n```\n\nNow you can seed the open LDAP server with a few users. \n\nJoin your LDAP container.\n\n```sh\ndocker exec -it my-openldap-container \"/bin/bash\"\n```\n\nThe command `ldapadd` needs of a file to run.\n\nLaunch this command to create a `bootstrap.ldif` with one organization, one singers group with Johnny user and a last group with Einstein as scientist.\n\n```sh\necho -e \"\ndn: ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: organizationalUnit\nou: People\n\ndn: ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: organizationalUnit\nou: Role\n\ndn: uid=johnny,ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: johnny\ncn: Johnny\nsn: Brown\nmail: johnny@otoroshi.tools\npostalCode: 88442\nuserPassword: password\n\ndn: uid=einstein,ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: einstein\ncn: Einstein\nsn: Wilson\nmail: einstein@otoroshi.tools\npostalCode: 88443\nuserPassword: password\n\ndn: cn=singers,ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: groupOfNames\ncn: singers\nmember: uid=johnny,ou=People,dc=otoroshi,dc=tools\n\ndn: cn=scientists,ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: groupOfNames\ncn: scientists\nmember: uid=einstein,ou=People,dc=otoroshi,dc=tools\n\" > bootstrap.ldif\n\nldapadd -x -w otoroshi -D \"cn=admin,dc=otoroshi,dc=tools\" -f bootstrap.ldif -v\n```\n\n### Create an Authentication configuration\n\n- Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n- Click on the cog icon on the top right\n- Then `Authentication configs` button\n- And add a new configuration when clicking on the `Add item` button\n- Select the `Ldap auth. provider` in the type selector field\n- Set a basic name and description\n- Then set `ldap://localhost:389` as `LDAP Server URL`and `dc=otoroshi,dc=tools` as `Search Base`\n- Create a group filter (in the next part, we'll change this filter to spread users in different groups with given rights) with \n - objectClass=groupOfNames as `Group filter` \n - All as `Tenant`\n - All as `Team`\n - Read/Write as `Rights`\n- Set the search filter as `(uid=${username})`\n- Set `cn=admin,dc=otoroshi,dc=tools` as `Admin username`\n- Set `otoroshi` as `Admin password`\n- At the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n\n At this point, your configuration should be similar to :\n \n\n\n\n> Dont' forget to save on the bottom page your configuration before to quit the page.\n\n- Test the connection when clicking on `Test admin connection` button. This should display a `It works!` message\n\n- Finally, test the user connection button and set `johnny/password` or `einstein/password` as credentials. This should display a `It works!` message\n\n> Dont' forget to save on the bottom page your configuration before to quit the page.\n\n\n### Connect to Otoroshi with LDAP authentication\n\nTo secure Otoroshi with your LDAP configuration, we have to register an **Authentication configuration** as a BackOffice Auth. configuration.\n\n- Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n- Scroll to the **BackOffice auth. settings**\n- Select your last Authentication configuration (created in the previous section)\n- Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n- Disconnect from your instance\n- Then click on the **Login using third-party** button (or navigate to @link:[http://otoroshi.oto.tools:8080/backoffice/auth0/login](http://otoroshi.oto.tools:8080/backoffice/auth0/login) { open=new })\n- Set `johnny/password` or `einstein/password` as credentials\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n\n#### Secure an app with LDAP authentication\n\nOnce the configuration is done, you can secure any of Otoroshi services. \n\n- Navigate to any created service\n- Jump to the `URL Patterns` section\n- Enable your service as `Public UI`\n- Then scroll to `Authentication` section\n- Enable `Enforce user authentication`\n- Select your Authentication config inside the list\n- Enable `Strict mode`\n- Don't forget to save your configuration\n\n\n\n\nNow you can try to call your defined service and see the login module appears.\n\n#### Manage LDAP users rights on Otoroshi\n\nFor each LDAP groups, you can affect a list of rights : \n\n- on an `Organization` : only resources of an organization\n- on a `Team` : only resources belonging to this team\n- and a level of rights : `Read`, `Write` or `Read/Write`\n\n\nStart by navigate to your authentication configuration (created in @ref:[previous](#create-an-authentication-configuration) step).\n\nThen, replace the values of the `Mapping group filter` field to match LDAP groups with Otoroshi rights.\n\n\n\n\nWith this configuration, Einstein is an administrator of Otoroshi with full rights (read / write) on all organizations.\n\nConversely, Johnny can't see any configuration pages (like the danger zone) because he has only the read rights on Otoroshi.\n\nYou can easily test this behaviour by @ref:[testing](#testing-your-configuration) with both credentials.\n\n\n#### Advanced usage of LDAP Authentication\n\nIn the previous section, we have define rights for each LDAP groups. But in some case, we want to have a finer granularity like set rights for a specific user. The last 4 fields of the authentication form cover this. \n\nLet's start by adding few properties for each connected users with `Extra metadata`.\n\n```json\n// Add this configuration in extra metadata part\n{\n \"provider\": \"OpenLDAP\"\n}\n```\n\nThe next field `Data override` is merged with extra metadata when a user connects to a `private app` or to the UI (inside Otoroshi, private app is a service secure by any authentication module). The `Email field name` is configured to match with the `mail` field from LDAP user data.\n\n```json \n{\n \"johnny@otoroshi.tools\": {\n \"stage_name\": \"Jean-Philippe Smet\"\n }\n}\n```\n\nIf you try to connect to an app with this configuration, the user result profile should be :\n\n```json\n{\n ...,\n \"metadata\": {\n \"lastname\": \"Hallyday\",\n \"stage_name\": \"Jean-Philippe Smet\"\n }\n}\n```\n\nLet's try to increase the Johnny rights with the `Additional rights group`.\n\nThis field supports the creation of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.\n\n```json\n// increase_johnny_rights is a virtual group which adds full access rights at johnny \n{\n \"increase_johnny_rights\": {\n \"rights\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ],\n \"users\": [\n \"johnny@otoroshi.tools\"\n ]\n }\n}\n```\n\nThe last field `Rights override` is useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights. \n\nTo resume, when Johnny connects to Otoroshi, he receives the rights to only read the default Organization (from **Mapping group filter**), then he is promote to administrator role (from **Additional rights group**) and finally his rights are reset with the last field **Rights override** to the read rights.\n\n```json \n{\n \"johnny@otoroshi.tools\": [\n {\n \"tenant\": \"*:r\",\n \"teams\": [\n \"*:r\"\n ]\n }\n ]\n}\n```\n\n\n\n\n\n\n\n\n" - }, - { - "name": "secure-the-communication-between-a-backend-app-and-otoroshi.md", - "id": "/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.md", - "url": "/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.html", - "title": "Secure the communication between a backend app and Otoroshi", - "content": "# Secure the communication between a backend app and Otoroshi\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n1. Navigate to http://otoroshi.oto.tools:8080/bo/services and create a new service\n2. Jump to `Service exposition settings` and add http://myservice.oto.tools as `Exposed domain`\n3. Jump to `Service targets` and add http://localhost:8081/ as `Target 1`\n4. Jump to the `URL Patterns` section\n5. Enable your service as `Public UI`\n6. Don't forget to save your service\n\nWe need of a simple service which handle the exchange protocol. For this tutorial, we'll use the following application, developed in NodeJS, which supports both versions of the exchange protocol.\n\nClone this @link:[repository](https://github.com/MAIF/otoroshi/blob/master/demos/challenge) and run the installation of the dependencies.\n\n```sh\ngit clone 'git@github.com:MAIF/otoroshi.git' --depth=1\ncd ./otoroshi/demos/challenge\nnpm install\nPORT=8081 node server.js\n```\n\nThe last command should return : \n\n```sh\nchallenge-verifier listening on http://0.0.0.0:8081\n```\n\nThis project runs an express client with one middleware. The middleware handles each request, and check if the header `State token header` is present in headers. By default, the incoming expected header is `Otoroshi-State` by the application and `Otoroshi-State-Resp` header in the headers of the return request. \n\nTry to call your service via http://myservice.oto.tools:8080/. This should return a successful response with all headers received by the backend app. \n\nNow try to disable the middleware in the nodejs file by commenting the following line. \n\n```js\n// app.use(OtoroshiMiddleware());\n```\n\nTry to call again your service. This time, Otoroshi breaks the return response from your backend service, and returns.\n\n```sh\nDownstream microservice does not seems to be secured. Cancelling request !\n```" - }, - { - "name": "secure-with-apikey.md", - "id": "/how-to-s/secure-with-apikey.md", - "url": "/how-to-s/secure-with-apikey.html", - "title": "Secure an api with api keys", - "content": "# Secure an api with api keys\n\n### Before you start\n\n@@include[fetch-and-start.md](../includes/fetch-and-start.md) { #init }\n\n### Create a simple service \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/services](http://otoroshi.oto.tools:8080/bo/dashboard/services) { open=new } and click on the `create new service` button\n2. Jump to `Service exposition settings` and add `http://myservice.oto.tools` as `Exposed domain`\n3. Jump to `Service targets` and add `https://mirror.otoroshi.io` as `Target 1`\n4. Jump to the `URL Patterns` section\n5. Enable your service as `Public UI`\n6. Open a new tab and navigate to @link:[http://myservice.oto.tools:8080](http://myservice.oto.tools:8080/) { open=new }\n\nWith this configuration, all routes are public, wihtout any authentication needed.\n\n### Secure routes with api key\n\nWith the previous configuration, all routes are public. In our case, we want to secure all routes prefix with `/api`.\n\nLet's return to the `URL Patterns` section. \nClick on **Make service a private api**. This button automatically add `/api` as default in `Private patterns` array. (Note that the field supports regex like. In our case, `/api.*` covers all routes starting by `/api`).\n\nSave your app and navigate to @link:[http://myservice.oto.tools:8080/api/test](http://myservice.oto.tools:8080/api/test) { open=new } again. If the service is configured, you should have a `Service Not found error`, and a success call, in the case you navigate to any other routes which are not starting by `/api/*` like @link:[http://myservice.oto.tools:8080/test/bar](http://myservice.oto.tools:8080/test/bar) { open=new }\n\nThe expected error on the `/api/test`, throws by the URL Patterns, indicate to the client that an api key is required to access to this part of the backend service.\n\n### Generate an api key to request secure services\n\nNavigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/apikeys/add](http://otoroshi.oto.tools:8080/bo/dashboard/apikeys/add) { open=new } or when clicking on the **Add apikey** button on the sidebar.\n\nThe only required fields of an Otoroshi api key are : \n\n* `ApiKey id`\n* `ApiKey Secret`\n* `ApiKey Name`\n\nThese fields are automatically generated by Otoroshi. However, you can override these values and indicate an additional description.\n\nTo simplify the rest of the tutorial, set the values:\n\n* `my-first-api-key-id` as `ApiKey Id`\n* `my-first-api-key-secret` as `ApiKey Secret`\n\nClick on **Create and stay on this ApiKey** button at the bottom of the page.\n\nNow you created the key, it's time to call our previous generated service with it.\n\nOtoroshi supports two methods to achieve that. \nOnce by passing Otoroshi api key in two headers : `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` (these headers names can be override on each service).\nAnd the second by passing Otoroshi api key in the authentication Header (basically the `Authorization` header) as a basic encoded value.\n\nLet's ahead and call our service :\n\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nAnd with the second method :\n\n```sh\ncurl -X GET \\\n -H 'Authorization: Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\n> Tips : To easily fill your headers, you can jump to the `Call examples` section in each api key view. In this section the header names are the default values and the service url is not set. You have to adapt these lines to your case. \n\n### Override defaults headers names for a service\n\nIn some case, we want to change the defaults headers names (and it's a quite good idea).\n\nLet's start by navigating to the `Api keys Constraints` section from the edit page of our sercice.\n\nThe first values to change are the headers names used to read the api key from client. Start by set :\n\n* `api-key-header-id` as `Custom client id header name`\n* `api-key-header-secret` as `Custom client secret header name`\n\nSave the service, and call the service again.\n\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nThis should output an error because Otoroshi are expecting the api keys in other headers.\n\n```json\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nCall one again the service but with the changed headers names.\n\n```sh\ncurl -X GET \\\n -H 'api-key-header-id: my-first-api-key-id' \\\n -H 'api-key-header-secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nWith this configuration, all others default services will accept the api keys with the `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers, while our service, will accept the `api-key-header-id` and `api-key-header-secret` headers.\n\n### Accept only api keys with expected values\n\nBy default, a secure service only accepts requests with api key. But all generated api keys are eligible to call our service and in some case, we want authorize only a couple of api keys.\n\nOne feature of Otoroshi is to restrict the list of accepted api keys by giving a list of `metadata` or/and `tags`. Each api key has a list of `tags` and `metadata`, which can be used by Otoroshi to forward or not a call with an api key. All api key metadata/tags can be forward to your service (see `Otoroshi exchange protocol` section of a service to get more information about `Send info. token`).\n\nLet's starting by accept only the api keys which come with the tag of `otoroshi` as value.\n\nJump to the last part of the `Api Keys Constraints` section, call `Routing constraints` (these constraints are used to forward a call to a service, only if all constraints are validated).\n\nIn our first case, set `otoroshi` in `One Tag in` array and save the service.\nThen call our service with :\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nThis should output :\n```json\n// Error reason : Our api key doesn't contains the expected tag.\n{\n \"Otoroshi-Error\": \"Bad API key\"\n}\n```\n\nNavigate to the edit page of our api key, and jump to the `Metadata and tags` section.\nIn this section, add `otoroshi` in `Tags` array, then save the api key. Call once again your call and you will normally get a successful response of our backend service.\n\nIn this example, we have restricted our service to be callable only with keys that have `otoroshi` as a tag.\n\nBut Otoroshi provides others behaviours. For each behaviour, *Api key used should*:\n\n* `All Tags in` : have all of the following tags\n* `No Tags in` : not have one of the following tags\n* `One Tag in` : have at least one of the following tags\n\n---\n\n* `All Meta. in` : have all of the following metadata entries\n* `No Meta. in` : not have one of the following metadata entries\n* `One Meta. in` : have at least one of the following metadata entries\n \n----\n\n* `One Meta key in` : have at least one of the following key in metadata\n* `All Meta key in` : have all of the following keys in metadata\n* `No Meta key in` : not have one of the following keys in metadata" - }, - { - "name": "secure-with-oauth1-client.md", - "id": "/how-to-s/secure-with-oauth1-client.md", - "url": "/how-to-s/secure-with-oauth1-client.html", - "title": "Secure an app with OAuth1 client flow", - "content": "# Secure an app with OAuth1 client flow\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Running an simple OAuth 1 server\n\nIn this tutorial, we'll instanciate a oauth 1 server with docker. If you alredy have the necessary, skip this section @ref:[to](#create-an-oauth-1-provider-module).\n\nLet's start by running the server\n\n```sh\ndocker run -d --name oauth1-server --rm \\\n -p 5000:5000 \\\n -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \\\n -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \\\n -e OAUTH1_REDIRECT_URI=http://otoroshi.oto.tools:8080/backoffice/auth0/callback \\\n ghcr.io/beryju/oauth1-test-server\n```\n\nWe created a oauth 1 server which accepts `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Redirect URI`. This URL is used by Otoroshi to retrieve a token and a profile at the end of an authentication process.\n\nAfter this command, the container logs should output :\n```sh \n127.0.0.1 - - [14/Oct/2021 12:10:49] \"HEAD /api/health HTTP/1.1\" 200 -\n```\n\n### Create an OAuth 1 provider module\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n1. Click on the cog icon on the top right\n1. Then **Authentication configs** button\n1. And add a new configuration when clicking on the **Add item** button\n2. Select the `Oauth1 provider` in the type selector field\n3. Set a basic name and description like `oauth1-provider`\n4. Set `2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET` as `Consumer key`\n5. Set `wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp` as `Consumer secret`\n6. Set `http://localhost:5000/oauth/request_token` as `Request Token URL`\n7. Set `http://localhost:5000/oauth/authorize` as `Authorize URL`\n8. Set `http://localhost:oauth/access_token` as `Access token URL`\n9. Set `http://localhost:5000/api/me` as `Profile URL`\n10. Set `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Callback URL`\n11. At the bottom of the page, disable the **secure** button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n At this point, your configuration should be similar to :\n\n\n\n\nWith this configuration, the connected user will receive default access on teams and organizations. If you want to change the access rights for a specific user, you can achieve it with the `Rights override` field and a configuration like :\n\n```json\n{\n \"foo@example.com\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ]\n}\n```\n\nSave your configuration at the bottom of the page, then navigate to the `danger zone` to use your module as a third-party connection to the Otoroshi UI.\n\n### Connect to Otoroshi with OAuth1 authentication\n\nTo secure Otoroshi with your OAuth1 configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n1. Scroll to the **BackOffice auth. settings**\n1. Select your last Authentication configuration (created in the previous section)\n1. Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the **Login using third-party** button (or navigate to http://otoroshi.oto.tools:8080)\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the oauth 1 server login page\n4. Set `example-user` as user and trust the user by clicking on `yes` button.\n5. Good work! You're connected to Otoroshi with an OAuth1 module.\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n### Secure an app with OAuth 1 authentication\n\nWith the previous configuration, you can secure any of Otoroshi services with it. \n\nThe first step is to apply a little change on the previous configuration. \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs](http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs) { open=new }.\n2. Create a new auth module configuration with the same values.\n3. Replace the `Callback URL` field to `http://privateapps.oto.tools:8080/privateapps/generic/callback` (we changed this value because the redirection of a logged user by a third-party server is cover by an other route by Otoroshi).\n4. Disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n> Note : an Otoroshi service is called a private app when it is protected by an authentication module.\n\nOur example server supports only one redirect URI. We need to kill it, and to create a new container with `http://otoroshi.oto.tools:8080/privateapps/generic/callback` as `OAUTH1_REDIRECT_URI`\n\n```sh\ndocker rm -f oauth1-server\ndocker run -d --name oauth1-server --rm \\\n -p 5000:5000 \\\n -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \\\n -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \\\n -e OAUTH1_REDIRECT_URI=http://privateapps.oto.tools:8080/privateapps/generic/callback \\\n ghcr.io/beryju/oauth1-test-server\n```\n\nOnce the authentication module and the new container created, we can define the authentication module on the service.\n\n1. Navigate to any created service\n2. Scroll to `Authentication` section\n3. Enable `Enforce user authentication`\n4. Select your Authentication config inside the list\n5. Enable `Strict mode`\n6. Don't forget to save your configuration.\n\nNow you can try to call your defined service and see the login module appears.\n\n> \n\nThe allow access to the user.\n\n> \n\nIf you had any errors, make sure of :\n\n* check if you are on http or https, and if the **secure cookie option** is enabled or not on the authentication module\n* check if your OAuth1 server has the REDIRECT_URI set on **privateapps/...**\n* Make sure your server supports POST or GET OAuth1 flow set on authentication module\n\nOnce the configuration is working, you can check, when connecting with an Otoroshi admin user, the `Private App session` created (use the cog at the top right of the page, and select `Priv. app sesssions`, or navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private) { open=new }).\n\nOne interesing feature is to check the profile of the connected user. In our case, when clicking on the `Profile` button of the right user, we should have : \n\n```json\n{\n \"email\": \"foo@example.com\",\n \"id\": 1,\n \"name\": \"test name\",\n \"screen_name\": \"example-user\"\n}\n```" - }, - { - "name": "secure-with-oauth2-client-credentials.md", - "id": "/how-to-s/secure-with-oauth2-client-credentials.md", - "url": "/how-to-s/secure-with-oauth2-client-credentials.html", - "title": "Secure an app with OAuth2 client_credential flow", - "content": "# Secure an app with OAuth2 client_credential flow\n\nOtoroshi makes it easy for your app to implement the [OAuth2 Client Credentials Flow](https://auth0.com/docs/authorization/flows/client-credentials-flow). Following successful authentication, the calling application will have access to an Access Token, which can be used to call your protected APIs.\n\n## Deployed the Client Credential Service\n\nThe Client Credential Service must be enabled as a global plugin on your Otoroshi instance. To achieve that, navigate to your otoroshi instance (in our case http://otoroshi.oto.tools:8080) on the danger zone (`top right cog icon / Danger zone` or at [/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone)).\n\nTo enable a plugin in global on Otoroshi, you must add it in the `Global Plugins` section.\n\nOpen the `Global Plugin` section, click on `enabled` (if not already done), and search the plugin named `Client Credential Service` of type `Sink`.\n\nTo show and add the default configuration on this plugin, click on the `show config. panel` an on the `Inject default config.` button. This button is available on each plugin and it's useful when you want to inject the default configuration.\n\nWhen you click on the `show config. panel`, you have the documentation of the plugin and its default configuration.\n\nThe client credential plugin has by default 4 parameters : \n\n* `domain`: a regex used to exposed routes on each matching domain (`default`: *)\n* `expiration`: duration until the token expire (in ms) (`default`: 3600000)\n* `defaultKeyPair`: a key pair used to sign the jwt token. By default, Otoroshi is deployed with an otoroshi-jwt-signing that you can visualize on the jwt verifiers certificates (`default`: \"otoroshi-jwt-signing\")\n* `secure`: if enabled, Otoroshi will expose routes only in the https requests case (`default`: true)\n\nIn this tutorial, we will set the configuration as following : \n\n* `domain`: *.oto.tools\n* `expiration`: 3600000\n* `defaultKeyPair`: otoroshi-jwt-signing\n* `secure`: false\n\nNow that the plugin is running, third routes are exposed on each matching domain of the regex.\n\n* `GET /.well-known/otoroshi/oauth/jwks.json` : retrieve all public keys presents in Otoroshi\n* `POST /.well-known/otoroshi/oauth/token/introspect` : validate and decode the token \n* `POST /.well-known/otoroshi/oauth/token` : generate a token with the fields provided\n\nOnce the global configuration saved, we can deployed a simple service to test it.\n\nLet's navigate to the services page, and create a new service with : \n\n1. `http://foo.oto.tools:8080` as `Exposed domain` in `Service exposition settings` section\n2. `https://mirror.otoroshi.io` as `Target 1` in `Service targets` section\n3. `/.*` as `Private patterns` in `URL Patterns` section (and remove all public patterns)\n\nIn `Api Keys Constraints`, disabled `From basic auth.`, `Allow client id only usage` and `From custom headers` button then saved the service.\n\nLet's make a first call, to check if the jwks are already exposed :\n\n```sh\ncurl 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/jwks.json'\n```\n\nThis should output a list of public keys : \n```sh\n{\n \"keys\": [\n {\n \"kty\": \"RSA\",\n \"e\": \"AQAB\",\n \"kid\": \"otoroshi-intermediate-ca\",\n ...\n }\n ...\n ]\n}\n``` \n\nLet's make a call on a route of this service. \n\n```sh\ncurl 'http://foo.oto.tools:8080/'\n```\n\nThis should output the expected error: \n```json\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nThe first step is to generate an api key. Navigate to the api keys page, and create an item with the following values (it will be more easy to use them in the next step) :\n\n* `my-id` as `ApiKey Id`\n* `my-secret` as `ApiKey Secret`\n\nThe next step is to ask a token by calling the exposed route `/.well-known/otoroshi/oauth/jwks.json`. The required fields are the grand type, the client and the client secret corresponding to our generated api key.\n\n```sh\ncurl -X POST 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/token' \\\n -H \"Content-Type: application/json\" \\\n -d '{\"grant_type\":\"client_credentials\", \"client_id\":\"my-id\", \"client_secret\":\"my-secret\"}'\n```\n\nWe have omit a parameter of the body which is named `scope`. This field can be used to set a bunch of scope on the generated access token.\n\nThe last command should output : \n\n```sh\n{\n \"access_token\": \"generated-token-xxxxx\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600\n}\n```\n\nOnce generate, we can call our api again : \n```sh\ncurl 'http://foo.oto.tools:8080/' \\\n -H \"Authorization: Bearer generated-token-xxxxx\"\n```\n\nThis should output a list of headers with a field named `Authorization` containing the previous access token.\n\n\n## Other possible configuration\n\nBy default, Otoroshi generate the access token with the specified key pair in the configuration. But, in some case, you want a specific key pair by client_id/client_secret.\nYou can achieve it when setting a `jwt-sign-keypair` metadata on your desired api key with the id of the key pair as value. \n" - }, - { - "name": "setup-otoroshi-cluster.md", - "id": "/how-to-s/setup-otoroshi-cluster.md", - "url": "/how-to-s/setup-otoroshi-cluster.html", - "title": "Setup an Otoroshi cluster", - "content": "# Setup an Otoroshi cluster\n\nIn this tutorial, we will deploy an Otoroshi cluster with one leader and 2 workers. We will add a load balancer in front of the workers and validate the installation by adding a header on the requests.\n\nLet's start by downloading the latest jar of Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nThen create an instance of Otoroshi and indicates with the `otoroshi.cluster.mode` environment variable that it will be the leader.\n\n```sh\njava -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar\n```\n\nOnce created, we have to create the two workers. For both workers, we have to set the ip and the url of their leader in the `otoroshi.cluster.leader.urls` environment variable.\n\nThe first worker will listen on the `:8082/:8092` ports\n```sh\njava \\\n -Dotoroshi.cluster.worker.name=worker-1 \\\n -Dhttp.port=8092 \\\n -Dhttps.port=9092 \\\n -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar\n```\n\nThe second worker will listen on the `:8083/:8093` ports\n```sh\njava \\\n -Dotoroshi.cluster.worker.name=worker-2 \\\n -Dhttp.port=8093 \\\n -Dhttps.port=9093 \\\n -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar\n```\n\nOnce launched, you can navigate to the @link:[cluster view](http://otoroshi.oto.tools:8091/bo/dashboard/cluster) { open=new }. If all is configured, you will see the leader, the 2 workers and a bunch of informations about each instance.\n\nTo complete our installation, we want to spread the incoming requests accross otoroshi worker instances. \n\nIn this tutorial, we will use haproxy has a TCP loadbalancer. If you don't have haproxy installed, you can use docker to run an haproxy instance as explained below.\n\nBut first, we need an haproxy configuration file named `haproxy.cfg` with the following content :\n\n```sh\nfrontend front_nodes_http\n bind *:8080\n mode tcp\n default_backend back_http_nodes\n timeout client 1m\n\nbackend back_http_nodes\n mode tcp\n balance roundrobin\n server node1 host.docker.internal:8092 # (1)\n server node2 host.docker.internal:8093 # (1)\n timeout connect 10s\n timeout server 1m\n```\n\nand run haproxy with this config file\n\nno docker\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #no_docker }\n\ndocker (on linux)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_linux }\n\ndocker (on macos)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_mac }\n\ndocker (on windows)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_windows }\n\nThe last step is to create a service, add a rule to add, in the headers, a specific value to identify the worker used.\n\nCreate this service, exposed on `http://myapi.oto.tools:xxxx`, which will forward all requests to the mirror `https://mirror.otoroshi.io`.\n\n```sh\ncurl -X POST http://otoroshi-api.oto.tools:8091/api/services \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret \\\n-d @- <<'EOF'\n{\n \"enforceSecureCommunication\": false,\n \"forceHttps\": false,\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"groupId\": \"default\",\n \"groups\": [\n \"default\"\n ],\n \"id\": \"myapi\",\n \"name\": \"myapi\",\n \"description\": \"myapi\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"api\",\n \"targetsLoadBalancing\": {\n \"type\": \"RoundRobin\"\n },\n \"targets\": [\n {\n \"host\": \"mirror.otoroshi.io\",\n \"scheme\": \"https\",\n \"weight\": 1,\n \"mtlsConfig\": {\n \"certs\": [],\n \"trustedCerts\": [],\n \"mtls\": false,\n \"loose\": false,\n \"trustAll\": false\n },\n \"tags\": [],\n \"metadata\": {},\n \"protocol\": \"HTTP\\/1.1\",\n \"predicate\": {\n \"type\": \"AlwaysMatch\"\n },\n \"ipAddress\": null\n }\n ],\n \"root\": \"\\/\",\n \"matchingRoot\": null,\n \"stripPath\": true,\n \"enabled\": true,\n \"publicPatterns\": [\n \"/.*\"\n ],\n \"kind\": \"ServiceDescriptor\",\n \"additionalHeaders\": {\n \"worker-name\": \"${config.otoroshi.cluster.worker.name}\"\n }\n}\nEOF\n```\n\nOnce created, call two times the service. If all is working, the header received by the backend service will have `worker-1` and `worker-2` as value.\n\n```sh\ncurl 'http://api.oto.tools:8080'\n## Response headers\n{\n ...\n \"worker-name\": \"worker-2\"\n ...\n}\n```\n\nThis should output `worker-1`, then `worker-2`, etc. Well done, your loadbalancing is working and your cluster is set up correctly.\n\n\n" - }, - { - "name": "tls-termination-using-own-certificates.md", - "id": "/how-to-s/tls-termination-using-own-certificates.md", - "url": "/how-to-s/tls-termination-using-own-certificates.html", - "title": "TLS termination using your own certificates", - "content": "# TLS termination using your own certificates\n\nThe goal of this tutorial is to expose a service via https using a certificate generated by openssl.\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\nTry to call the service.\n\n```sh\ncurl 'http://myservice.oto.tools:8080'\n```\n\nThis should output something like\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.opunmaif.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"x-forwarded-port\": \"443\",\n \"opun-proxied-host\": \"mirror.otoroshi.io\",\n \"otoroshi-request-id\": \"1463145856319359618\",\n \"otoroshi-proxied-host\": \"myservice.oto.tools:8080\",\n \"opun-gateway-request-id\": \"1463145856554240100\",\n \"x-forwarded-proto\": \"https\",\n },\n \"body\": \"\"\n}\n```\n\nLet's try to call the service in https.\n\n```sh\ncurl 'https://myservice.oto.tools:8443'\n```\n\nThis should output\n\n```sh\ncurl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myservice.oto.tools:8443\n```\n\nTo fix it, we have to generate a certificate and import it in Otoroshi to match the domain `myservice.oto.tools`.\n\n> If you already had a certificate you can skip the next set of commands and directly import your certificate in Otoroshi\n\nWe will use openssl to generate a private key and a self-signed certificate.\n\n```sh\nopenssl genrsa -out myservice.key 4096\n# remove pass phrase\nopenssl rsa -in myservice.key -out myservice.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key myservice.key -out myservice.cer -subj \"/CN=myservice.oto.tools\"\n```\n\nCheck the content of the certificate \n\n```sh\nopenssl x509 -in myservice.cer -text\n```\n\nThis should contains something like\n\n```sh\nCertificate:\n Data:\n Version: 1 (0x0)\n Serial Number: 9572962808320067790 (0x84d9fef455f188ce)\n Signature Algorithm: sha256WithRSAEncryption\n Issuer: CN=myservice.oto.tools\n Validity\n Not Before: Nov 23 14:25:55 2021 GMT\n Not After : Nov 23 14:25:55 2022 GMT\n Subject: CN=myservice.oto.tools\n Subject Public Key Info:\n Public Key Algorithm: rsaEncryption\n Public-Key: (4096 bit)\n Modulus:\n...\n```\n\nOnce generated, go back to Otoroshi and navigate to the certificates management page (`top right cog icon / SSL/TLS certificates` or at @link:[`/bo/dashboard/certificates`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates)) and click on `Add item`.\n\nSet `myservice-certificate` as `name` and `description`.\n\nDrop the `myservice.cer` file or copy the content to the `Certificate full chain` field.\n\nDo the same action for the `myservice.key` file in the `Certificate private key` field.\n\nSet your passphrase password in the `private key password` field if you added one.\n\nLet's try the same call to the service.\n\n```sh\ncurl 'https://myservice.oto.tools:8443'\n```\n\nAn error should occurs due to the untrsuted received certificate server\n\n```sh\ncurl: (60) SSL certificate problem: self signed certificate\nMore details here: https://curl.haxx.se/docs/sslcerts.html\n\ncurl failed to verify the legitimacy of the server and therefore could not\nestablish a secure connection to it. To learn more about this situation and\nhow to fix it, please visit the web page mentioned above.\n```\n\nEnd this tutorial by trusting the certificate server \n\n```sh\ncurl 'https://myservice.oto.tools:8443' --cacert myservice.cer\n```\n\nThis should finally output\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.opunmaif.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"x-forwarded-port\": \"443\",\n \"opun-proxied-host\": \"mirror.otoroshi.io\",\n \"otoroshi-request-id\": \"1463158439730479893\",\n \"otoroshi-proxied-host\": \"myservice.oto.tools:8443\",\n \"opun-gateway-request-id\": \"1463158439558515871\",\n \"x-forwarded-proto\": \"https\",\n \"sozu-id\": \"01FN6MGKSYZNJYHEMP4R5PJ4Q5\"\n },\n \"body\": \"\"\n}\n```\n\n" - }, - { - "name": "tls-using-lets-encrypt.md", - "id": "/how-to-s/tls-using-lets-encrypt.md", - "url": "/how-to-s/tls-using-lets-encrypt.html", - "title": "TLS termination using Let's Encrypt", - "content": "# TLS termination using Let's Encrypt\n\nAs you know, Otoroshi is capable of doing TLS termination for your services. You can import your own certificates, generate certificates from scratch and you can also use the @link:[ACME protocol](https://datatracker.ietf.org/doc/html/rfc8555) to generate certificates. One of the most popular service offering ACME certificates creation is @link:[Let's Encrypt](https://letsencrypt.org/).\n\n@@@ warning\nIn order to make this tutorial work, your otoroshi instance MUST be accessible from the internet in order to be reachable by Let's Encrypt ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.\n@@@\n\n@@@ note\nthis tutorial can work with any ACME provider with the same rules. your otoroshi instance MUST be accessible by the ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.\n@@@\n\n## Setup let's encrypt on otoroshi\n\nGo on the danger zone page by clicking on the [`cog icon / Danger Zone`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates). Scroll to the `Let's Encrypt settings` section. Enable it, and specify the address of the ACME server (for production Let's Encrypt it's `acme://letsencrypt.org`, for testing, it's `acme://letsencrypt.org/staging`. Any ACME server address should work). You can also add one or more email addresses or contact urls that will be included in your Let's Encrypt account. You don't have to fill the `public/private key` inputs as they will be automatically generated on the first usage.\n\n## Creating let's encrypt certificate from FQDNs\n\nYou can go to the certificates page by clicking on the [`cog icon / SSL/TLS Certificates`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates). Here, click on the `+ Let's Encrypt certificate` button. A popup will show up to ask you the FQDN that you want for you certificate. Once done, click on the `Create` button. A few moment later, you will be redirected on a brand new certificate generated by Let's encrypt. You can now enjoy accessing your service behind the FQDN with TLS.\n\n## Creating let's encrypt certificate from a service\n\nYou can go to any service page and enable the flag `Issue Let's Encrypt cert.`. Do not forget to save your service. A few moment later, the certificates will be available in the certificates page and you can will be able to enjoy accessing your service with TLS.\n" - }, - { - "name": "fetch-and-start.md", - "id": "/includes/fetch-and-start.md", - "url": "/includes/fetch-and-start.html", - "title": "", - "content": "\nIf you already have an up and running otoroshi instance, you can skip the following instructions\n\nLet's start by downloading the latest Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nthen you can run start Otoroshi :\n\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\nNow you can log into Otoroshi at @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new } with `admin@otoroshi.io/password`\n" - }, - { - "name": "initialize.md", - "id": "/includes/initialize.md", - "url": "/includes/initialize.html", - "title": "", - "content": "\n\nIf you already have an up and running otoroshi instance, you can skip the following instructions\n\n\n@@@div { .instructions }\n\n
\nI want to follow the instructions to start an instance of Otorohi\n\n
\n\nLet's start by downloading the latest Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nthen you can run start Otoroshi :\n\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\nNow you can log into Otoroshi at http://otoroshi.oto.tools:8080 with `admin@otoroshi.io/password`\n\nCreate a service, exposed on `http://myservice.oto.tools:8080`, which will forward all requests to the mirror `https://mirror.otoroshi.io`. Each call to this service will returned the body and the headers received by the mirror.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n -d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"my-service\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"myservice\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\\/.*\"],\"privatePatterns\":[],\"kind\":\"ServiceDescriptor\"}' \\\n -H \"Content-type: application/json\" \\\n -u admin-api-apikey-id:admin-api-apikey-secret\n```\n\n\n@@@\n" - }, - { - "name": "index.md", - "id": "/index.md", - "url": "/index.html", - "title": "Otoroshi", - "content": "# Otoroshi\n\n**Otoroshi** is a layer of lightweight api management on top of a modern http reverse proxy written in Scala and developped by the MAIF OSS team that can handle all the calls to and between your microservices without service locator and let you change configuration dynamicaly at runtime.\n\n\n> *The Otoroshi is a large hairy monster that tends to lurk on the top of the torii gate in front of Shinto shrines. It's a hostile creature, but also said to be the guardian of the shrine and is said to leap down from the top of the gate to devour those who approach the shrine for only self-serving purposes.*\n\n@@@ div { .centered-img }\n[![build](https://github.com/MAIF/otoroshi/actions/workflows/server_build_and_test.yaml/badge.svg)](https://github.com/MAIF/otoroshi/actions/workflows/server_build_and_test.yaml) [![Join the chat at https://gitter.im/MAIF/otoroshi](https://badges.gitter.im/MAIF/otoroshi.svg)](https://gitter.im/MAIF/otoroshi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [ ![Download](https://img.shields.io/github/release/MAIF/otoroshi.svg) ](hhttps://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\n## Installation\n\nYou can download the latest build of Otoroshi as a @ref:[fat jar](./install/get-otoroshi.md#from-jar-file), as a @ref:[zip package](./install/get-otoroshi.md#from-zip) or as a @ref:[docker image](./install/get-otoroshi.md#from-docker).\n\nYou can install and run Otoroshi with this little bash snippet\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\njava -jar otoroshi.jar\n```\n\nor using docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi:1.5.11\n```\n\nnow open your browser to http://otoroshi.oto.tools:8080/, **log in with the credential generated in the logs** and explore by yourself, if you want better instructions, just go to the @ref:[Quick Start](./getting-started.md) or directly to the @ref:[installation instructions](./install/get-otoroshi.md)\n\n## Documentation\n\n* @ref:[About Otoroshi](./about.md)\n* @ref:[Architecture](./architecture.md)\n* @ref:[Features](./features.md)\n* @ref:[Getting started](./getting-started.md)\n* @ref:[Install Otoroshi](./install/index.md)\n* @ref:[Main entities](./entities/index.md)\n* @ref:[Detailed topics](./topics/index.md)\n* @ref:[How to's](./how-to-s/index.md)\n* @ref:[Plugins](./plugins/index.md)\n* @ref:[Admin REST API](./api.md)\n* @ref:[Deploy to production](./deploy/index.md)\n* @ref:[Developing Otoroshi](./dev.md)\n* @ref:[Otoroshi next](./next/index.md)\n\n## Discussion\n\nJoin the [Otoroshi](https://gitter.im/MAIF/otoroshi) channel on the [MAIF Gitter](https://gitter.im/MAIF) { open=new }\n\n## Sources\n\nThe sources of Otoroshi are available on @link:[Github](https://github.com/MAIF/otoroshi) { open=new }.\n\n## Logo\n\nYou can find the official Otoroshi logo @link:[on GitHub](https://github.com/MAIF/otoroshi/blob/master/resources/otoroshi-logo.png) { open=new }. The Otoroshi logo has been created by François Galioto ([@fgalioto](https://twitter.com/fgalioto))\n\n## Changelog\n\nEvery release, along with the migration instructions, is documented on the @link:[Github Releases](https://github.com/MAIF/otoroshi/releases) { open=new } page. A condensed version of the changelog is available on @link:[github](https://github.com/MAIF/otoroshi/blob/master/CHANGELOG.md) { open=new }\n\n## Patrons\n\nThe work on Otoroshi was funded by MAIF with the help of the community.\n\n## Licence\n\nOtoroshi is Open Source and available under the @link:[Apache 2 License](https://opensource.org/licenses/Apache-2.0) { open=new }\n\n@@@ index\n\n* [About Otoroshi](./about.md)\n* [Architecture](./architecture.md)\n* [Features](./features.md)\n* [Getting started](./getting-started.md)\n* [Install Otoroshi](./install/index.md)\n* [Main entities](./entities/index.md)\n* [Detailed topics](./topics/index.md)\n* [How to's](./how-to-s/index.md)\n* [Plugins](./plugins/index.md)\n* [Admin REST API](./api.md)\n* [Deploy to production](./deploy/index.md)\n* [Developing Otoroshi](./dev.md)\n* [Otoroshi next](./next/index.md)\n\n@@@\n\n" - }, - { - "name": "get-otoroshi.md", - "id": "/install/get-otoroshi.md", - "url": "/install/get-otoroshi.html", - "title": "Get Otoroshi", - "content": "# Get Otoroshi\n\nAll release can be bound on the releases page of the @link:[repository](https://github.com/MAIF/otoroshi/releases) { open=new }.\n\n## From zip\n\n```sh\n# Download the latest version\nwget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi-1.5.11.zip\nunzip ./otoroshi-1.5.11.zip\ncd otoroshi-1.5.11\n```\n\n## From jar file\n\n```sh\n# Download the latest version\nwget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar\n```\n\n## From Docker\n\n```sh\n# Download the latest version\ndocker pull maif/otoroshi:1.5.11-jdk11\n```\n\n## From Sources\n\nTo build Otoroshi from sources, just go to the @ref:[dev documentation](../dev.md)\n" - }, - { - "name": "index.md", - "id": "/install/index.md", - "url": "/install/index.html", - "title": "Install", - "content": "# Install\n\nIn this sections, you will find informations about how to install and run Otoroshi\n\n* @ref:[Get Otoroshi](./get-otoroshi.md)\n* @ref:[Setup Otoroshi](./setup-otoroshi.md)\n* @ref:[Run Otoroshi](./run-otoroshi.md)\n\n@@@ index\n\n* [Get Otoroshi](./get-otoroshi.md)\n* [Setup Otoroshi](./setup-otoroshi.md)\n* [Run Otoroshi](./run-otoroshi.md)\n\n@@@\n" - }, - { - "name": "run-otoroshi.md", - "id": "/install/run-otoroshi.md", - "url": "/install/run-otoroshi.html", - "title": "Run Otoroshi", - "content": "# Run Otoroshi\n\nNow you are ready to run Otoroshi. You can run the following command with some tweaks depending on the way you want to configure Otoroshi. If you want to pass a custom configuration file, use the `-Dconfig.file=/path/to/file.conf` flag in the following commands.\n\n## From .zip file\n\n```sh\ncd otoroshi-vx.x.x\n./bin/otoroshi\n```\n\n## From .jar file\n\nFor Java 11\n\n```sh\njava -jar otoroshi.jar\n```\n\nif you want to run the jar file for on a JDK above JDK11, you'll have to add the following flags\n\n```sh\njava \\\n --add-opens=java.base/javax.net.ssl=ALL-UNNAMED \\\n --add-opens=java.base/sun.net.www.protocol.file=ALL-UNNAMED \\\n --add-exports=java.base/sun.security.x509=ALL-UNNAMED \\\n --add-opens=java.base/sun.security.ssl=ALL-UNNAMED \\\n -Dlog4j2.formatMsgNoLookups=true \\\n -jar otoroshi.jar\n```\n\n## From docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi\n```\n\nYou can also pass useful args like :\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi -Dconfig.file=/usr/app/otoroshi/conf/otoroshi.conf -Dlogger.file=/usr/app/otoroshi/conf/otoroshi.xml\n```\n\nIf you want to provide your own config file, you can read @ref:[the documentation about config files](./setup-otoroshi.md).\n\nYou can also provide some ENV variable using the `--env` flag to customize your Otoroshi instance.\n\nThe list of possible env variables is available @ref:[here](./setup-otoroshi.md).\n\nYou can use a volume to provide configuration like :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd):/usr/app/otoroshi/conf\" maif/otoroshi\n```\n\nYou can also use a volume if you choose to use `filedb` datastore like :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd)/filedb:/usr/app/otoroshi/filedb\" maif/otoroshi -Dotoroshi.storage=file\n```\n\nYou can also use a volume if you choose to use exports files :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd):/usr/app/otoroshi/imports\" maif/otoroshi -Dotoroshi.importFrom=/usr/app/otoroshi/imports/export.json\n```\n\n## Run examples\n\n```sh\n$ java \\\n -Xms2G \\\n -Xmx8G \\\n -Dhttp.port=8080 \\\n -Dotoroshi.importFrom=/home/user/otoroshi.json \\\n -Dconfig.file=/home/user/otoroshi.conf \\\n -jar ./otoroshi.jar\n\n[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[warn] otoroshi-env - Importing from: /home/user/otoroshi.json\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n```\n\nIf you choose to start Otoroshi without importing existing data, Otoroshi will create a new admin user and print the login details in the log. When you will log into the admin dashboard, Otoroshi will ask you to create another account to avoid security issues.\n\n```sh\n$ java \\\n -Xms2G \\\n -Xmx8G \\\n -Dhttp.port=8080 \\\n -jar otoroshi.jar\n\n[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[warn] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / HHUsiF2UC3OPdmg0lGngEv3RrbIwWV5W\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n```\n" - }, - { - "name": "setup-otoroshi.md", - "id": "/install/setup-otoroshi.md", - "url": "/install/setup-otoroshi.html", - "title": "Setup Otoroshi", - "content": "# Setup Otoroshi\n\nin this section we are going to configure otoroshi before running it for the first time\n\n## Setup the database\n\nRight now, Otoroshi supports multiple datastore. You can choose one datastore over another depending on your use case.\n\n@@@div { .plugin .platform } \n
Redis
\n\n
Recommended
\n\nThe **redis** datastore is quite nice when you want to easily deploy several Otoroshi instances.\n\n\n\n@link:[Documentation](https://redis.io/topics/quickstart)\n@@@\n\n@@@div { .plugin .platform } \n
In memory
\n\nThe **in-memory** datastore is kind of interesting. It can be used for testing purposes, but it is also a good candidate for production because of its fastness.\n\n\n\n@ref:[Start with](../getting-started.md)\n@@@\n\n@@@div { .plugin .platform } \n
Cassandra
\n\n
Clustering
\n\nExperimental support, should be used in cluster mode for leaders\n\n\n\n@link:[Documentation](https://cassandra.apache.org/doc/latest/cassandra/getting_started/installing.html)\n@@@\n\n@@@div { .plugin .platform } \n
Postgresql
\n\n
Clustering
\n\nOr any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)\n\n\n\n@link:[Documentation](https://www.postgresql.org/docs/10/tutorial-install.html)\n@@@\n\n@@@div { .plugin .platform } \n\n
FileDB
\n\nThe **filedb** datastore is pretty handy for testing purposes, but is not supposed to be used in production mode. \nNot suitable for production usage.\n\n\n\n@@@\n\n\n@@@ div { .centered-img }\n\n@@@\n\nthe first thing to setup is what kind of datastore you want to use with the `otoroshi.storage` setting\n\n```conf\notoroshi {\n storage = \"inmemory\" # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n storage = ${?APP_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n storage = ${?OTOROSHI_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n}\n```\n\ndepending on the value you chose, you will be able to configure your datastore with the following configuration\n\ninmemory\n: @@snip [inmemory.conf](../snippets/datastores/inmemory.conf) \n\nfile\n: @@snip [file.conf](../snippets/datastores/file.conf) \n\nhttp\n: @@snip [http.conf](../snippets/datastores/http.conf) \n\ns3\n: @@snip [s3.conf](../snippets/datastores/s3.conf) \n\nredis\n: @@snip [redis.conf](../snippets/datastores/redis.conf) \n\nredis with lettuce\n: @@snip [lettuce.conf](../snippets/datastores/lettuce.conf) \n\npostgresql\n: @@snip [pg.conf](../snippets/datastores/pg.conf) \n\ncassandra\n: @@snip [inmemory.conf](../snippets/datastores/cassandra.conf) \n\n## Setup your hosts before running\n\nBy default, Otoroshi starts with domain `oto.tools` that automatically targets `127.0.0.1` with no changes to your `/etc/hosts` file. Of course you can change the domain value, you have to add the values in your `/etc/hosts` file according to the setting you put in Otoroshi configuration or define the right ip address at the DNS provider level\n\n* `otoroshi.domain` => `mydomain.org`\n* `otoroshi.backoffice.subdomain` => `otoroshi`\n* `otoroshi.privateapps.subdomain` => `privateapps`\n* `otoroshi.adminapi.exposedSubdomain` => `otoroshi-api`\n* `otoroshi.adminapi.targetSubdomain` => `otoroshi-admin-internal-api`\n\nfor instance if you want to change the default domain and use something like `otoroshi.mydomain.org`, then start otoroshi like \n\n```sh\njava -Dotoroshi.domain=mydomain.org -jar otoroshi.jar\n```\n\n@@@ warning\nOtoroshi cannot be accessed using `http://127.0.0.1:8080` or `http://localhost:8080` because Otoroshi uses Otoroshi to serve it's own UI and API. When otoroshi starts with an empty database, it will create a service descriptor for that using `otoroshi.domain` and the settings listed on this page and in the here that serve Otoroshi API and UI on `http://otoroshi-api.${otoroshi.domain}` and `http://otoroshi.${otoroshi.domain}`.\nOnce the descriptor is saved in database, if you want to change `otoroshi.domain`, you'll have to edit the descriptor in the database or restart Otoroshi with an empty database.\n@@@\n\n@@@ warning\nif your otoroshi instance runs behind a reverse proxy (L4 / L7) or inside a docker container where exposed ports (that you will use to access otoroshi) are not the same that the ones configured in otoroshi (`http.port` and `https.port`), you'll have to configure otoroshi exposed port to avoid bad redirection URLs when using authentication modules and other otoroshi tools. To do that, just set the values of the exposed ports in `otoroshi.exposed-ports.http = $theExposedHttpPort` (OTOROSHI_EXPOSED_PORTS_HTTP) and `otoroshi.exposed-ports.https = $theExposedHttpsPort` (OTOROSHI_EXPOSED_PORTS_HTTPS)\n@@@\n\n## Setup your configuration file\n\nThere is a lot of things you can configure in Otoroshi. By default, Otoroshi provides a configuration that should be enough for testing purpose. But you'll likely need to update this configuration when you'll need to move into production.\n\nIn this page, any configuration property can be set at runtime using a `-D` flag when launching Otoroshi like \n\n```sh\njava -Dhttp.port=8080 -jar otoroshi.jar\n```\n\nor\n\n```sh\n./bin/otoroshi -Dhttp.port=8080 \n```\n\nif you want to define your own config file and use it on an otoroshi instance, use the following flag\n\n```sh\njava -Dconfig.file=/path/to/otoroshi.conf -jar otoroshi.jar\n``` \n\n### Example of a custom. configuration file\n\n```conf\ninclude \"application.conf\"\n\nhttp.port = 8080\n\napp {\n storage = \"inmemory\"\n importFrom = \"./my-state.json\"\n env = \"prod\"\n domain = \"oto.tools\"\n rootScheme = \"http\"\n snowflake {\n seed = 0\n }\n events {\n maxSize = 1000\n }\n backoffice {\n subdomain = \"otoroshi\"\n session {\n exp = 86400000\n }\n }\n privateapps {\n subdomain = \"privateapps\"\n session {\n exp = 86400000\n }\n }\n adminapi {\n targetSubdomain = \"otoroshi-admin-internal-api\"\n exposedSubdomain = \"otoroshi-api\"\n defaultValues {\n backOfficeGroupId = \"admin-api-group\"\n backOfficeApiKeyClientId = \"admin-api-apikey-id\"\n backOfficeApiKeyClientSecret = \"admin-api-apikey-secret\"\n backOfficeServiceId = \"admin-api-service\"\n }\n }\n claim {\n sharedKey = \"mysecret\"\n }\n filedb {\n path = \"./filedb/state.ndjson\"\n }\n}\n\nplay.http {\n session {\n secure = false\n httpOnly = true\n maxAge = 2592000000\n domain = \".oto.tools\"\n cookieName = \"oto-sess\"\n }\n}\n```\n\n### Reference configuration\n\n@@snip [reference.conf](../snippets/reference.conf) \n\n### More config. options\n\nSee default configuration at\n\n* @link:[Base configuration](https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/base.conf) { open=new }\n* @link:[Application configuration](https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/application.conf) { open=new }\n\n## Configuration with env. variables\n\nEevery property in the configuration file can be overriden by an environment variable if it has env variable override written like `${?ENV_VARIABLE}`).\n\n## Reference configuration for env. variables\n\n@@snip [reference-env.conf](../snippets/reference-env.conf) \n" - }, - { - "name": "built-in-plugins.md", - "id": "/next/built-in-plugins.md", - "url": "/next/built-in-plugins.html", - "title": "Built-in plugins", - "content": "# Built-in plugins\n\nOtoroshi next provides some plugins out of the box. Here is the available plugins with their documentation and reference configuration\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AdditionalHeadersIn }\n\n## Additional headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AdditionalHeadersIn`\n\n### Description\n\nThis plugin adds headers in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AdditionalHeadersOut }\n\n## Additional headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AdditionalHeadersOut`\n\n### Description\n\nThis plugin adds headers in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AllowHttpMethods }\n\n## Allowed HTTP methods\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AllowHttpMethods`\n\n### Description\n\nThis plugin verifies the current request only uses allowed http methods\n\n\n\n### Default configuration\n\n```json\n{\n \"allowed\" : [ ],\n \"forbidden\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ApikeyCalls }\n\n## Apikeys\n\n### Defined on steps\n\n - `MatchRoute`\n - `ValidateAccess`\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ApikeyCalls`\n\n### Description\n\nThis plugin expects to find an apikey to allow the request to pass\n\n\n\n### Default configuration\n\n```json\n{\n \"extractors\" : {\n \"basic\" : {\n \"enabled\" : true,\n \"header_name\" : null,\n \"query_name\" : null\n },\n \"custom_headers\" : {\n \"enabled\" : true,\n \"client_id_header_name\" : null,\n \"client_secret_header_name\" : null\n },\n \"client_id\" : {\n \"enabled\" : true,\n \"header_name\" : null,\n \"query_name\" : null\n },\n \"jwt\" : {\n \"enabled\" : true,\n \"secret_signed\" : true,\n \"keypair_signed\" : true,\n \"include_request_attrs\" : false,\n \"max_jwt_lifespan_sec\" : null,\n \"header_name\" : null,\n \"query_name\" : null,\n \"cookie_name\" : null\n }\n },\n \"routing\" : {\n \"enabled\" : false\n },\n \"validate\" : true,\n \"pass_with_user\" : false,\n \"wipe_backend_request\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ApikeyQuotas }\n\n## Apikey quotas\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ApikeyQuotas`\n\n### Description\n\nIncrements quotas for the currents apikey. Useful when 'legacy checks' are disabled on a service/globally or when apikey are extracted in a custom fashion.\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AuthModule }\n\n## Authentication\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AuthModule`\n\n### Description\n\nThis plugin applies an authentication module\n\n\n\n### Default configuration\n\n```json\n{\n \"pass_with_apikey\" : false,\n \"auth_module\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.BuildMode }\n\n## Build mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.BuildMode`\n\n### Description\n\nThis plugin displays a build page\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.CanaryMode }\n\n## Canary mode\n\n### Defined on steps\n\n - `PreRoute`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.CanaryMode`\n\n### Description\n\nThis plugin can split a portion of the traffic to canary backends\n\n\n\n### Default configuration\n\n```json\n{\n \"traffic\" : 0.2,\n \"targets\" : [ ],\n \"root\" : \"/\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ContextValidation }\n\n## Context validator\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ContextValidation`\n\n### Description\n\nThis plugin validates the current context using JSONPath validators.\n\nThis plugin let you configure a list of validators that will check if the current call can pass.\nA validator is composed of a [JSONPath](https://goessner.net/articles/JsonPath/) that will tell what to check and a value that is the expected value.\nThe JSONPath will be applied on a document that will look like\n\n```js\n{\n \"snowflake\" : \"1516772930422308903\",\n \"apikey\" : { // current apikey\n \"clientId\" : \"vrmElDerycXrofar\",\n \"clientName\" : \"default-apikey\",\n \"metadata\" : {\n \"foo\" : \"bar\"\n },\n \"tags\" : [ ]\n },\n \"user\" : null, // current user\n \"request\" : {\n \"id\" : 1,\n \"method\" : \"GET\",\n \"headers\" : {\n \"Host\" : \"ctx-validation-next-gen.oto.tools:9999\",\n \"Accept\" : \"*/*\",\n \"User-Agent\" : \"curl/7.64.1\",\n \"Authorization\" : \"Basic dnJtRWxEZXJ5Y1hyb2ZhcjpvdDdOSTkyVGI2Q2J4bWVMYU9UNzJxamdCU2JlRHNLbkxtY1FBcXBjVjZTejh0Z3I1b2RUOHAzYjB5SEVNRzhZ\",\n \"Remote-Address\" : \"127.0.0.1:58929\",\n \"Timeout-Access\" : \"\",\n \"Raw-Request-URI\" : \"/foo\",\n \"Tls-Session-Info\" : \"Session(1650461821330|SSL_NULL_WITH_NULL_NULL)\"\n },\n \"cookies\" : [ ],\n \"tls\" : false,\n \"uri\" : \"/foo\",\n \"path\" : \"/foo\",\n \"version\" : \"HTTP/1.1\",\n \"has_body\" : false,\n \"remote\" : \"127.0.0.1\",\n \"client_cert_chain\" : null\n },\n \"config\" : {\n \"validators\" : [ {\n \"path\" : \"$.apikey.metadata.foo\",\n \"value\" : \"bar\"\n } ]\n },\n \"global_config\" : { ... }, // global config\n \"attrs\" : {\n \"otoroshi.core.SnowFlake\" : \"1516772930422308903\",\n \"otoroshi.core.ElCtx\" : {\n \"requestId\" : \"1516772930422308903\",\n \"requestSnowflake\" : \"1516772930422308903\",\n \"requestTimestamp\" : \"2022-04-20T15:37:01.548+02:00\"\n },\n \"otoroshi.next.core.Report\" : \"otoroshi.next.proxy.NgExecutionReport@277b44e2\",\n \"otoroshi.core.RequestStart\" : 1650461821545,\n \"otoroshi.core.RequestWebsocket\" : false,\n \"otoroshi.core.RequestCounterOut\" : 0,\n \"otoroshi.core.RemainingQuotas\" : {\n \"authorizedCallsPerSec\" : 10000000,\n \"currentCallsPerSec\" : 0,\n \"remainingCallsPerSec\" : 10000000,\n \"authorizedCallsPerDay\" : 10000000,\n \"currentCallsPerDay\" : 2,\n \"remainingCallsPerDay\" : 9999998,\n \"authorizedCallsPerMonth\" : 10000000,\n \"currentCallsPerMonth\" : 269,\n \"remainingCallsPerMonth\" : 9999731\n },\n \"otoroshi.next.core.MatchedRoutes\" : \"MutableList(route_022825450-e97d-42ed-8e22-b23342c1c7c8)\",\n \"otoroshi.core.RequestNumber\" : 1,\n \"otoroshi.next.core.Route\" : { ... }, // current route as json\n \"otoroshi.core.RequestTimestamp\" : \"2022-04-20T15:37:01.548+02:00\",\n \"otoroshi.core.ApiKey\" : { ... }, // current apikey as json\n \"otoroshi.core.User\" : { ... }, // current user as json\n \"otoroshi.core.RequestCounterIn\" : 0\n },\n \"route\" : { ... },\n \"token\" : null // current valid jwt token if one\n}\n```\n\nthe expected value support some syntax tricks like\n\n* `Not(value)` on a string to check if the current value does not equals another value\n* `Regex(regex)` on a string to check if the current value matches the regex\n* `RegexNot(regex)` on a string to check if the current value does not matches the regex\n* `Wildcard(*value*)` on a string to check if the current value matches the value with wildcards\n* `WildcardNot(*value*)` on a string to check if the current value does not matches the value with wildcards\n* `Contains(value)` on a string to check if the current value contains a value\n* `ContainsNot(value)` on a string to check if the current value does not contains a value\n* `Contains(Regex(regex))` on an array to check if one of the item of the array matches the regex\n* `ContainsNot(Regex(regex))` on an array to check if one of the item of the array does not matches the regex\n* `Contains(Wildcard(*value*))` on an array to check if one of the item of the array matches the wildcard value\n* `ContainsNot(Wildcard(*value*))` on an array to check if one of the item of the array does not matches the wildcard value\n* `Contains(value)` on an array to check if the array contains a value\n* `ContainsNot(value)` on an array to check if the array does not contains a value\n\nfor instance to check if the current apikey has a metadata name `foo` with a value containing `bar`, you can write the following validator\n\n```js\n{\n \"path\": \"$.apikey.metadata.foo\",\n \"value\": \"Contains(bar)\"\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"validators\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Cors }\n\n## CORS\n\n### Defined on steps\n\n - `PreRoute`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Cors`\n\n### Description\n\nThis plugin applies CORS rules\n\n\n\n### Default configuration\n\n```json\n{\n \"allow_origin\" : \"*\",\n \"expose_headers\" : [ ],\n \"allow_headers\" : [ ],\n \"allow_methods\" : [ ],\n \"excluded_patterns\" : [ ],\n \"max_age\" : null,\n \"allow_credentials\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.DisableHttp10 }\n\n## Disable HTTP/1.0\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.DisableHttp10`\n\n### Description\n\nThis plugin forbids HTTP/1.0 requests\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.EndlessHttpResponse }\n\n## Endless HTTP responses\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.EndlessHttpResponse`\n\n### Description\n\nThis plugin returns 128 Gb of 0 to the ip addresses is in the list\n\n\n\n### Default configuration\n\n```json\n{\n \"finger\" : false,\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ForceHttpsTraffic }\n\n## Force HTTPS traffic\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ForceHttpsTraffic`\n\n### Description\n\nThis plugin verifies the current request uses HTTPS\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalMaintenanceMode }\n\n## Global Maintenance mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalMaintenanceMode`\n\n### Description\n\nThis plugin displays a maintenance page for every services. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalPerIpAddressThrottling }\n\n## Global per ip address throttling \n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalPerIpAddressThrottling`\n\n### Description\n\nEnforce global per ip address throttling. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalThrottling }\n\n## Global throttling \n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalThrottling`\n\n### Description\n\nEnforce global throttling. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GzipResponseCompressor }\n\n## Gzip compression\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GzipResponseCompressor`\n\n### Description\n\nThis plugin can compress responses using gzip\n\n\n\n### Default configuration\n\n```json\n{\n \"excluded_patterns\" : [ ],\n \"allowed_list\" : [ \"text/*\", \"application/javascript\", \"application/json\" ],\n \"blocked_list\" : [ ],\n \"buffer_size\" : 8192,\n \"chunked_threshold\" : 102400,\n \"compression_level\" : 5\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.HeadersValidation }\n\n## Headers validation\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.HeadersValidation`\n\n### Description\n\nThis plugin validates the values of incoming request headers\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.IpAddressAllowedList }\n\n## IP allowed list\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.IpAddressAllowedList`\n\n### Description\n\nThis plugin verifies the current request ip address is in the allowed list\n\n\n\n### Default configuration\n\n```json\n{\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.IpAddressBlockList }\n\n## IP block list\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.IpAddressBlockList`\n\n### Description\n\nThis plugin verifies the current request ip address is not in the blocked list\n\n\n\n### Default configuration\n\n```json\n{\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQ }\n\n## JQ\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQ`\n\n### Description\n\nThis plugin let you transform JSON bodies (in requests and responses) using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"request\" : \".\",\n \"response\" : \"\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQRequest }\n\n## JQ transform request\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQRequest`\n\n### Description\n\nThis plugin let you transform request JSON body using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : \".\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQResponse }\n\n## JQ transform response\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQResponse`\n\n### Description\n\nThis plugin let you transform JSON response using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : \".\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JsonToXmlRequest }\n\n## request body json-to-xml\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JsonToXmlRequest`\n\n### Description\n\nThis plugin transform incoming request body from json to xml and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JsonToXmlResponse }\n\n## response body json-to-xml\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JsonToXmlResponse`\n\n### Description\n\nThis plugin transform response body from json to xml and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JwtVerification }\n\n## Jwt verifiers\n\n### Defined on steps\n\n - `ValidateAccess`\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JwtVerification`\n\n### Description\n\nThis plugin verifies the current request with one or more jwt verifier\n\n\n\n### Default configuration\n\n```json\n{\n \"verifiers\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MaintenanceMode }\n\n## Maintenance mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MaintenanceMode`\n\n### Description\n\nThis plugin displays a maintenance page\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MissingHeadersIn }\n\n## Missing headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MissingHeadersIn`\n\n### Description\n\nThis plugin adds headers (if missing) in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MissingHeadersOut }\n\n## Missing headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MissingHeadersOut`\n\n### Description\n\nThis plugin adds headers (if missing) in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MockResponses }\n\n## Mock Responses\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MockResponses`\n\n### Description\n\nThis plugin returns mock responses\n\n\n\n### Default configuration\n\n```json\n{\n \"responses\" : [ ],\n \"pass_through\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OtoroshiChallenge }\n\n## Otoroshi challenge token\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OtoroshiChallenge`\n\n### Description\n\nThis plugin adds a jwt challenge token to the request to a backend and expects a response with a matching token\n\n\n\n### Default configuration\n\n```json\n{\n \"version\" : 2,\n \"ttl\" : 30,\n \"request_header_name\" : null,\n \"response_header_name\" : null,\n \"algo_to_backend\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"algo_from_backend\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"state_resp_leeway\" : 10\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OtoroshiInfos }\n\n## Otoroshi info. token\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OtoroshiInfos`\n\n### Description\n\nThis plugin adds a jwt info. token to the request to a backend\n\n\n\n### Default configuration\n\n```json\n{\n \"version\" : \"Latest\",\n \"ttl\" : 30,\n \"header_name\" : null,\n \"algo\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OverrideHost }\n\n## Override host header\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OverrideHost`\n\n### Description\n\nThis plugin override the current Host header with the Host of the backend target\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.PublicPrivatePaths }\n\n## Public/Private paths\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.PublicPrivatePaths`\n\n### Description\n\nThis plugin allows or forbid request based on path patterns\n\n\n\n### Default configuration\n\n```json\n{\n \"strict\" : false,\n \"private_patterns\" : [ ],\n \"public_patterns\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.QueryTransformer }\n\n## Query param transformer\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.QueryTransformer`\n\n### Description\n\nThis plugin can modify the query params of the request\n\n\n\n### Default configuration\n\n```json\n{\n \"remove\" : [ ],\n \"rename\" : { },\n \"add\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RBAC }\n\n## RBAC\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RBAC`\n\n### Description\n\nThis plugin check if current user/apikey/jwt token has the right role\n\n\n\n### Default configuration\n\n```json\n{\n \"allow\" : [ ],\n \"deny\" : [ ],\n \"allow_all\" : false,\n \"deny_all\" : false,\n \"jwt_path\" : null,\n \"apikey_path\" : null,\n \"user_path\" : null,\n \"role_prefix\" : null,\n \"roles\" : \"roles\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ReadOnlyCalls }\n\n## Read only requests\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ReadOnlyCalls`\n\n### Description\n\nThis plugin verifies the current request only reads data\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Redirection }\n\n## Redirection\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Redirection`\n\n### Description\n\nThis plugin redirects the current request elsewhere\n\n\n\n### Default configuration\n\n```json\n{\n \"code\" : 303,\n \"to\" : \"https://www.otoroshi.io\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RemoveHeadersIn }\n\n## Remove headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RemoveHeadersIn`\n\n### Description\n\nThis plugin removes headers in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"header_names\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RemoveHeadersOut }\n\n## Remove headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RemoveHeadersOut`\n\n### Description\n\nThis plugin removes headers in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"header_names\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Robots }\n\n## Robots\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Robots`\n\n### Description\n\nThis plugin provides all the necessary tool to handle search engine robots\n\n\n\n### Default configuration\n\n```json\n{\n \"robot_txt_enabled\" : true,\n \"robot_txt_content\" : \"User-agent: *\\nDisallow: /\\n\",\n \"meta_enabled\" : true,\n \"meta_content\" : \"noindex,nofollow,noarchive\",\n \"header_enabled\" : true,\n \"header_content\" : \"noindex, nofollow, noarchive\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RoutingRestrictions }\n\n## Routing Restrictions\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RoutingRestrictions`\n\n### Description\n\nThis plugin apply routing restriction `method domain/path` on the current request/route\n\n\n\n### Default configuration\n\n```json\n{\n \"allow_last\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"not_found\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SOAPAction }\n\n## SOAP action\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SOAPAction`\n\n### Description\n\nThis plugin is able to call SOAP actions and expose it as a rest endpoint\n\n\n\n### Default configuration\n\n```json\n{\n \"url\" : null,\n \"envelope\" : \"\",\n \"action\" : null,\n \"preserve_query\" : true,\n \"charset\" : null,\n \"jq_request_filter\" : null,\n \"jq_response_filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SendOtoroshiHeadersBack }\n\n## Send otoroshi headers back\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SendOtoroshiHeadersBack`\n\n### Description\n\nThis plugin adds response header containing useful informations about the current call\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SnowMonkeyChaos }\n\n## Snow Monkey Chaos\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SnowMonkeyChaos`\n\n### Description\n\nThis plugin introduce some chaos into you life\n\n\n\n### Default configuration\n\n```json\n{\n \"large_request_fault\" : null,\n \"large_response_fault\" : null,\n \"latency_injection_fault\" : null,\n \"bad_responses_fault\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.StaticResponse }\n\n## Static Response\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.StaticResponse`\n\n### Description\n\nThis plugin returns static responses\n\n\n\n### Default configuration\n\n```json\n{\n \"status\" : 200,\n \"headers\" : { },\n \"body\" : \"\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.TcpTunnel }\n\n## TCP Tunnel\n\n### Defined on steps\n\n - `HandlesTunnel`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.TcpTunnel`\n\n### Description\n\nThis plugin creates TCP tunnels through otoroshi\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.UdpTunnel }\n\n## UDP Tunnel\n\n### Defined on steps\n\n - `HandlesTunnel`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.UdpTunnel`\n\n### Description\n\nThis plugin creates UDP tunnels through otoroshi\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.W3CTracing }\n\n## W3C Trace Context\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.W3CTracing`\n\n### Description\n\nThis plugin propagates W3C Trace Context spans and can export it to Jaeger or Zipkin\n\n\n\n### Default configuration\n\n```json\n{\n \"kind\" : \"noop\",\n \"endpoint\" : \"http://localhost:3333/spans\",\n \"timeout\" : 30000,\n \"baggage\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XForwardedHeaders }\n\n## X-Forwarded-* headers\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XForwardedHeaders`\n\n### Description\n\nThis plugin adds all the X-Forwarder-* headers to the request for the backend target\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XmlToJsonRequest }\n\n## request body xml-to-json\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XmlToJsonRequest`\n\n### Description\n\nThis plugin transform incoming request body from xml to json and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XmlToJsonResponse }\n\n## response body xml-to-json\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XmlToJsonResponse`\n\n### Description\n\nThis plugin transform response body from xml to json and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n\n\n" - }, - { - "name": "engine.md", - "id": "/next/engine.md", - "url": "/next/engine.html", - "title": "New proxy engine", - "content": "# New proxy engine\n\nStarting from the `1.5.3` release, otoroshi offers a new plugin that implements the next generation of the proxy engine. \nThis engine has been designed based on our 5 years experience building, maintaining and running the previous one. \nIt tries to fix all the drawback we may have encountered during those years and highly improve performances, user experience, reporting and debugging capabilities. \nThe new engine is fully plugin oriented in order to spend CPU cycles only on useful stuff.\nYou can enable this plugin only on some domain names so you can easily A/B test the new engine.\nThe new proxy engine is designed to be more reactive and more efficient generally.\nIt is also designed to be very efficient on path routing where it wasn't the old engines strong suit.\n\n@@@ warning\nThis engine is **experimental** and might not work as expected !\n@@@\n\n## Enabling the new engine\n\nTo enable the new proxy engine on an otoroshi instance, just add the plugin in the `global plugins` section of the danger zone, inject the default configuration, enable it and in `domains` add the values of the desired domains (let say we want to use the new engine on `api.foo.bar`. It is possible to use `*.foo.bar` if that's what you want to do).\n\nThe next time a request hits the `api.foo.bar` domain, the new engine will handle it instead of the previous one.\n\n```json\n{\n \"NextGenProxyEngine\" : {\n \"enabled\" : true,\n \"debug_headers\" : false,\n \"reporting\": true,\n \"domains\" : [ \"api.foo.bar\" ],\n \"deny_domains\" : [ ],\n }\n}\n```\n\nif you need to enable global plugin with the new engine, you can add the following configuration in the `global plugins` configuration object \n\n```javascript\n{\n ...\n \"ng\": {\n \"slots\": [\n {\n \"plugin\": \"cp:otoroshi.next.plugins.W3CTracing\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"baggage\": {\n \"foo\": \"bar\"\n }\n }\n },\n {\n \"plugin\": \"cp:otoroshi.next.plugins.wrappers.RequestSinkWrapper\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"plugin\": \"cp:otoroshi.plugins.apikeys.ClientCredentialService\",\n \"ClientCredentialService\": {\n \"domain\": \"ccs-next-gen.oto.tools\",\n \"expiration\": 3600000,\n \"defaultKeyPair\": \"otoroshi-jwt-signing\",\n \"secure\": false\n }\n }\n }\n ]\n }\n ...\n}\n```\n\n## Entities\n\nThis plugin introduces new entities that will replace (one day maybe) service descriptors:\n\n - `routes`: a unique routing rule based on hostname, path, method and headers that will execute a bunch of plugins\n - `services`: multiple routing rules based on hostname, path, method and headers that will execute the same list of plugins\n - `targets`: how to contact a backend either by using a domain name or an ip address, supports mtls\n - `backends`: a list of targets to contact a backend\n\n## Entities sync\n\nA new behavior introduced for the new proxy engine is the entities sync job. To avoid unecessary operations on the underlying datastore when routing requests, a new job has been setup in otoroshi that synchronize the content of the datastore (at least a part of it) with an in-memory cache. Because of it, the propagation of changes between an admin api call and the actual result on routing can be longer than before. When a node creates, updates, or deletes an entity via the admin api, other nodes need to wait for the next poll to purge the old cached entity and start using the new one. You can change the interval between syncs with the configuration key `otoroshi.next.state-sync-interval` or the env. variable `OTOROSHI_NEXT_STATE_SYNC_INTERVAL`. The default value is `10000` and the unit is `milliseconds`\n\n@@@ warning\nBecause of entities sync, memory consumption of otoroshi will be significantly higher than previous versions. You can use `otoroshi.next.monitor-proxy-state-size=true` config (or `OTOROSHI_NEXT_MONITOR_PROXY_STATE_SIZE` env. variable) to monitor the actual memory size of the entities cache. This will produce the `ng-proxy-state-size-monitoring` metric in standard otoroshi metrics\n@@@\n\n## Automatic conversion\n\nThe new engine uses new entities for its configuration, but in order to facilitate transition between the old world and the new world, all the `service descriptors` of an otoroshi instance are automatically converted live into `routes` periodically. Any `service descriptor` should still work as expected through the new engine while enjoying all the perks.\n\n@@@ warning\nthe experimental nature of the engine can imply unexpected behaviors for converted service descriptors\n@@@\n\n## Routing\n\nthe new proxy engine introduces a new router that has enhanced capabilities and performances. The router can handle thousands of routes declarations without compromising performances.\n\nThe new route allow routes to be matched on a combination of\n\n* hostname\n* path\n* header values\n * where values can be `exact_value`, or `Regex(value_regex)`, or `Wildcard(value_with_*)`\n* query param values\n * where values can be `exact_value`, or `Regex(value_regex)`, or `Wildcard(value_with_*)`\n\npatch matching works \n\n* exactly\n * matches `/api/foo` with `/api/foo` and not with `/api/foo/bar`\n* starting with value (default behavior, like the previous engine)\n * matches `/api/foo` with `/api/foo` but also with `/api/foo/bar`\n\npath matching can also include wildcard paths and even path params\n\n* plain old path: `subdomain.domain.tld/api/users`\n* wildcard path: `subdomain.domain.tld/api/users/*/bills`\n* named path params: `subdomain.domain.tld/api/users/:id/bills`\n* named regex path params: `subdomain.domain.tld/api/users/$id<[0-9]+>/bills`\n\nhostname matching works on \n\n* exact values\n * `subdomain.domain.tld`\n* wildcard values like\n * `*.domain.tld`\n * `subdomain.*.tld`\n\nas path matching can now include named path params, it is possible to perform a ful url rewrite on the target path like \n\n* input: `subdomain.domain.tld/api/users/$id<[0-9]+>/bills`\n* output: `target.domain.tld/apis/v1/basic_users/${req.pathparams.id}/all_bills`\n\n## Plugins\n\nthe new route entity defines a plugin pipline where any plugin can be enabled or not and can be active only on some paths. \nEach plugin slot in the pipeline holds the plugin id and the plugin configuration. \n\nYou can also enable debugging only on a plugin instance instead of the whole route (see [the debugging section](#debugging))\n\n```javascript\n{ \n ...\n \"plugins\" : [ {\n \"enabled\" : true,\n \"debug\" : false,\n \"plugin\" : \"cp:otoroshi.next.plugins.OverrideHost\",\n \"include\" : [ ],\n \"exclude\" : [ ],\n \"config\" : { }\n }, {\n \"enabled\" : true,\n \"debug\" : false,\n \"plugin\" : \"cp:otoroshi.next.plugins.ApikeyCalls\",\n \"include\" : [ ],\n \"exclude\" : [ \"/openapi.json\" ],\n \"config\" : { }\n } ]\n}\n```\n\nyou can find the list of built-in plugins @ref:[here](./built-in-plugins.md)\n\n## Using legacy plugins\n\nif you need to use legacy otoroshi plugins with the new engine, you can use several wrappers in order to do so\n\n* `otoroshi.next.plugins.wrappers.PreRoutingWrapper`\n* `otoroshi.next.plugins.wrappers.AccessValidatorWrapper`\n* `otoroshi.next.plugins.wrappers.RequestSinkWrapper`\n* `otoroshi.next.plugins.wrappers.RequestTransformerWrapper`\n* `otoroshi.next.plugins.wrappers.CompositeWrapper`\n\nto use it, just declare a plugin slot with the right wrapper and in the config, declare the `plugin` you want to use and its configuration like:\n\n```javascript\n{\n \"plugin\": \"cp:otoroshi.next.plugins.wrappers.PreRoutingWrapper\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"plugin\": \"cp:otoroshi.plugins.jwt.JwtUserExtractor\",\n \"JwtUserExtractor\": {\n \"verifier\" : \"$ref\",\n \"strict\" : true,\n \"namePath\" : \"name\",\n \"emailPath\": \"email\",\n \"metaPath\" : null\n }\n }\n}\n```\n\n## Reporting\n\nby default, any request hiting the new engine will generate an execution report with informations about how the request pipeline steps were performed. It is possible to export those reports as `RequestFlowReport` events using classical data exporter. By default, exporting for reports is not enabled, you must enable the `export_reporting` flag on a `route` or `service`.\n\n```javascript\n{\n \"@id\": \"8efac472-07bc-4a80-8d27-4236309d7d01\",\n \"@timestamp\": \"2022-02-15T09:51:25.402+01:00\",\n \"@type\": \"RequestFlowReport\",\n \"@product\": \"otoroshi\",\n \"@serviceId\": \"service_548f13bb-a809-4b1d-9008-fae3b1851092\",\n \"@service\": \"demo-service\",\n \"@env\": \"prod\",\n \"route\": {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\",\n \"name\" : \"hey\",\n \"description\" : \"hey\",\n \"tags\" : [ \"env:prod\" ],\n \"metadata\" : { },\n \"enabled\" : true,\n \"debug_flow\" : true,\n \"export_reporting\" : false,\n \"groups\" : [ \"default\" ],\n \"frontend\" : {\n \"domains\" : [ \"hey-next-gen.oto.tools/\", \"hey.oto.tools/\" ],\n \"strip_path\" : true,\n \"exact\" : false,\n \"headers\" : { },\n \"methods\" : [ ]\n },\n \"backend\" : {\n \"targets\" : [ {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n } ],\n \"target_refs\" : [ ],\n \"root\" : \"/\",\n \"rewrite\" : false,\n \"load_balancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"client\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n }\n },\n \"backend_ref\" : null,\n \"plugins\" : [ ]\n },\n \"report\": {\n \"id\" : \"ab73707b3-946b-4853-92d4-4c38bbaac6d6\",\n \"creation\" : \"2022-02-15T09:51:25.402+01:00\",\n \"termination\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 5,\n \"duration_ns\" : 5905522,\n \"overhead\" : 4,\n \"overhead_ns\" : 4223215,\n \"overhead_in\" : 2,\n \"overhead_in_ns\" : 2687750,\n \"overhead_out\" : 1,\n \"overhead_out_ns\" : 1535465,\n \"state\" : \"Successful\",\n \"steps\" : [ {\n \"task\" : \"start-handling\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085402,\n \"stop_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 177430,\n \"ctx\" : null\n }, {\n \"task\" : \"check-concurrent-requests\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085402,\n \"stop_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 145242,\n \"ctx\" : null\n }, {\n \"task\" : \"find-route\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 497119,\n \"ctx\" : {\n \"found_route\" : {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\",\n \"name\" : \"hey\",\n \"description\" : \"hey\",\n \"tags\" : [ \"env:prod\" ],\n \"metadata\" : { },\n \"enabled\" : true,\n \"debug_flow\" : true,\n \"export_reporting\" : false,\n \"groups\" : [ \"default\" ],\n \"frontend\" : {\n \"domains\" : [ \"hey-next-gen.oto.tools/\", \"hey.oto.tools/\" ],\n \"strip_path\" : true,\n \"exact\" : false,\n \"headers\" : { },\n \"methods\" : [ ]\n },\n \"backend\" : {\n \"targets\" : [ {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n } ],\n \"target_refs\" : [ ],\n \"root\" : \"/\",\n \"rewrite\" : false,\n \"load_balancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"client\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n }\n },\n \"backend_ref\" : null,\n \"plugins\" : [ ]\n },\n \"matched_path\" : \"\",\n \"exact\" : true,\n \"params\" : { },\n \"matched_routes\" : [ \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\" ]\n }\n }, {\n \"task\" : \"compute-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 105151,\n \"ctx\" : {\n \"disabled_plugins\" : [ ],\n \"filtered_plugins\" : [ ]\n }\n }, {\n \"task\" : \"tenant-check\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 26097,\n \"ctx\" : null\n }, {\n \"task\" : \"check-global-maintenance\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 14132,\n \"ctx\" : null\n }, {\n \"task\" : \"call-before-request-callbacks\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 56671,\n \"ctx\" : null\n }, {\n \"task\" : \"extract-tracking-id\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 5207,\n \"ctx\" : null\n }, {\n \"task\" : \"call-pre-route-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 39786,\n \"ctx\" : null\n }, {\n \"task\" : \"call-access-validator-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 25311,\n \"ctx\" : null\n }, {\n \"task\" : \"enforce-global-limits\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 296617,\n \"ctx\" : {\n \"remaining_quotas\" : {\n \"authorizedCallsPerSec\" : 10000000,\n \"currentCallsPerSec\" : 10000000,\n \"remainingCallsPerSec\" : 10000000,\n \"authorizedCallsPerDay\" : 10000000,\n \"currentCallsPerDay\" : 10000000,\n \"remainingCallsPerDay\" : 10000000,\n \"authorizedCallsPerMonth\" : 10000000,\n \"currentCallsPerMonth\" : 10000000,\n \"remainingCallsPerMonth\" : 10000000\n }\n }\n }, {\n \"task\" : \"choose-backend\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 368899,\n \"ctx\" : {\n \"backend\" : {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n }\n }, {\n \"task\" : \"transform-request\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 506363,\n \"ctx\" : null\n }, {\n \"task\" : \"call-backend\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 2,\n \"duration_ns\" : 2163470,\n \"ctx\" : null\n }, {\n \"task\" : \"transform-response\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 279887,\n \"ctx\" : null\n }, {\n \"task\" : \"stream-response\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 382952,\n \"ctx\" : null\n }, {\n \"task\" : \"trigger-analytics\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085408,\n \"stop_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 812036,\n \"ctx\" : null\n }, {\n \"task\" : \"request-success\",\n \"start\" : 1644915085408,\n \"start_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"stop\" : 1644915085408,\n \"stop_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 0,\n \"ctx\" : null\n } ]\n }\n}\n```\n\n## Debugging\n\nwith the new reporting capabilities, the new engine also have debugging capabilities built in. In you enable the `debug_flow` flag on a route (or service), the resulting `RequestFlowReport` will be enriched with contextual informations between each plugins of the route plugin pipeline\n\n@@@ note\nyou can also use the `Try it` feature of the new route designer UI to get debug reports automatically for a specific call\n@@@\n\n## HTTP traffic capture\n\nusing the `capture` flag, a `TrafficCaptureEvent` is generated for each http request/response. This event will contains request and response body. Those events can be exported using @ref:[data exporters](../entities/data-exporters.md) as usual. You can also use the @ref:[GoReplay file exporter](../entities/data-exporters.md#goreplay-file) that is specifically designed to ingest those events and create [GoReplay](https://goreplay.org/) files (`.gor`)\n\n@@@ warning\nthis feature can have actual impact on CPU and RAM consumption\n@@@\n\n```json\n{\n \"@id\": \"d5998b0c4-cb08-43e6-9921-27472c7a56e0\",\n \"@timestamp\": 1651828801115,\n \"@type\": \"TrafficCaptureEvent\",\n \"@product\": \"otoroshi\",\n \"@serviceId\": \"route_2b2670879-131c-423d-b755-470c7b1c74b1\",\n \"@service\": \"test-server\",\n \"@env\": \"prod\",\n \"route\": {\n \"id\": \"route_2b2670879-131c-423d-b755-470c7b1c74b1\",\n \"name\": \"test-server\"\n },\n \"request\": {\n \"id\": \"152250645825034725600000\",\n \"int_id\": 115,\n \"method\": \"POST\",\n \"headers\": {\n \"Host\": \"test-server-next-gen.oto.tools:9999\",\n \"Accept\": \"*/*\",\n \"Cookie\": \"fifoo=fibar\",\n \"User-Agent\": \"curl/7.64.1\",\n \"Content-Type\": \"application/json\",\n \"Content-Length\": \"13\",\n \"Remote-Address\": \"127.0.0.1:57660\",\n \"Timeout-Access\": \"\",\n \"Raw-Request-URI\": \"/\",\n \"Tls-Session-Info\": \"Session(1651828041285|SSL_NULL_WITH_NULL_NULL)\"\n },\n \"cookies\": [\n {\n \"name\": \"fifoo\",\n \"value\": \"fibar\",\n \"path\": \"/\",\n \"domain\": null,\n \"http_only\": true,\n \"max_age\": null,\n \"secure\": false,\n \"same_site\": null\n }\n ],\n \"tls\": false,\n \"uri\": \"/\",\n \"path\": \"/\",\n \"version\": \"HTTP/1.1\",\n \"has_body\": true,\n \"remote\": \"127.0.0.1\",\n \"client_cert_chain\": null,\n \"body\": \"{\\\"foo\\\":\\\"bar\\\"}\"\n },\n \"backend_request\": {\n \"url\": \"http://localhost:3000/\",\n \"method\": \"POST\",\n \"headers\": {\n \"Host\": \"localhost\",\n \"Accept\": \"*/*\",\n \"Cookie\": \"fifoo=fibar\",\n \"User-Agent\": \"curl/7.64.1\",\n \"Content-Type\": \"application/json\",\n \"Content-Length\": \"13\"\n },\n \"version\": \"HTTP/1.1\",\n \"client_cert_chain\": null,\n \"cookies\": [\n {\n \"name\": \"fifoo\",\n \"value\": \"fibar\",\n \"domain\": null,\n \"path\": \"/\",\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": true\n }\n ],\n \"id\": \"152260631569472064900000\",\n \"int_id\": 33,\n \"body\": \"{\\\"foo\\\":\\\"bar\\\"}\"\n },\n \"backend_response\": {\n \"status\": 200,\n \"headers\": {\n \"Date\": \"Fri, 06 May 2022 09:20:01 GMT\",\n \"Connection\": \"keep-alive\",\n \"Set-Cookie\": \"foo=bar\",\n \"Content-Type\": \"application/json\",\n \"Transfer-Encoding\": \"chunked\"\n },\n \"cookies\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\",\n \"domain\": null,\n \"path\": null,\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": false\n }\n ],\n \"id\": \"152260631569472064900000\",\n \"status_txt\": \"OK\",\n \"http_version\": \"HTTP/1.1\",\n \"body\": \"{\\\"headers\\\":{\\\"host\\\":\\\"localhost\\\",\\\"accept\\\":\\\"*/*\\\",\\\"user-agent\\\":\\\"curl/7.64.1\\\",\\\"content-type\\\":\\\"application/json\\\",\\\"cookie\\\":\\\"fifoo=fibar\\\",\\\"content-length\\\":\\\"13\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"/\\\",\\\"body\\\":\\\"{\\\\\\\"foo\\\\\\\":\\\\\\\"bar\\\\\\\"}\\\"}\"\n },\n \"response\": {\n \"id\": \"152250645825034725600000\",\n \"status\": 200,\n \"headers\": {\n \"Date\": \"Fri, 06 May 2022 09:20:01 GMT\",\n \"Connection\": \"keep-alive\",\n \"Set-Cookie\": \"foo=bar\",\n \"Content-Type\": \"application/json\",\n \"Transfer-Encoding\": \"chunked\"\n },\n \"cookies\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\",\n \"domain\": null,\n \"path\": null,\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": false\n }\n ],\n \"status_txt\": \"OK\",\n \"http_version\": \"HTTP/1.1\",\n \"body\": \"{\\\"headers\\\":{\\\"host\\\":\\\"localhost\\\",\\\"accept\\\":\\\"*/*\\\",\\\"user-agent\\\":\\\"curl/7.64.1\\\",\\\"content-type\\\":\\\"application/json\\\",\\\"cookie\\\":\\\"fifoo=fibar\\\",\\\"content-length\\\":\\\"13\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"/\\\",\\\"body\\\":\\\"{\\\\\\\"foo\\\\\\\":\\\\\\\"bar\\\\\\\"}\\\"}\"\n },\n \"user-agent-details\": null,\n \"origin-details\": null,\n \"instance-number\": 0,\n \"instance-name\": \"dev\",\n \"instance-zone\": \"local\",\n \"instance-region\": \"local\",\n \"instance-dc\": \"local\",\n \"instance-provider\": \"local\",\n \"instance-rack\": \"local\",\n \"cluster-mode\": \"Leader\",\n \"cluster-name\": \"otoroshi-leader-9hnv5HUXpbCZD7Ee\"\n}\n```\n\n## openapi import\n\nas the new router offers possibility to match exactly on a single path and a single method, and with the help of the `service` entity, it is now pretty easy to import openapi document as `service` entities. To do that, a new api has been made available to perform the translation. Be aware that this api **DOES NOT** save the entity and just return the result of the translation. \n\n```sh\ncurl -X POST \\\n -H 'Content-Type: application/json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n 'http://otoroshi-api.oto.tools:8080/api/experimental/services/_openapi' \\\n -d '{\"domain\":\"oto-api-proxy.oto.tools\",\"openapi\":\"https://raw.githubusercontent.com/MAIF/otoroshi/master/otoroshi/public/openapi.json\"}'\n```\n\n@@@ div { .centered-img }\n\n@@@\n\n" - }, - { - "name": "index.md", - "id": "/next/index.md", - "url": "/next/index.html", - "title": "Otoroshi Next", - "content": "# Otoroshi Next\n\nIn this sections, you will find informations about Otoroshi next \n\n* @ref:[New proxy engine](./engine.md)\n* @ref:[Secrets management](./secrets.md)\n* @ref:[Built in plugins](./built-in-plugins.md)\n\n@@@ index\n\n* [New proxy engine](./engine.md)\n* [Secrets management](./secrets.md)\n* [Built in plugins](./built-in-plugins.md)\n\n@@@\n" - }, - { - "name": "secrets.md", - "id": "/next/secrets.md", - "url": "/next/secrets.html", - "title": "Secrets management", - "content": "# Secrets management\n\n@@@ warning\n\nthis feature is **EXPERIMENTAL** and might not work as expected\n\n@@@\n\nSecrets are generally confidential values that should not appear in plain text in the application. There are several products that help you store, retrieve, and rotate these secrets securely. Otoroshi offers a mechanism to set up references to these secrets in its entities to benefits from the perks of your existing secrets management infrastructure. This feature only work with the @ref:[new proxy engine](./engine.md).\n\nA secret can be anything you want like an apikey secret, a certificate private key or password, a jwt verifier signing key, a password to a proxy, a value for a header, etc.\n\n## Enable secrets management in otoroshi\n\nBy default secrets management is disbaled. You can enable it by setting `otoroshi.vaults.enabled` or `${OTOROSHI_VAULTS_ENABLED}` to `true`.\n\n## Global configuration\n\nSecrets management can be only configured using otoroshi static configuration file (also using jvm args mechanism). \nThe configuration is located at `otoroshi.vaults` where you can find the global configuration of the secrets management system and the configurations for each enabled secrets management backends. Basically it looks like\n\n```conf\nvaults {\n enabled = false\n enabled = ${?OTOROSHI_VAULTS_ENABLED}\n secrets-ttl = 300000 # 5 minutes\n secrets-ttl = ${?OTOROSHI_VAULTS_SECRETS_TTL}\n cached-secrets = 10000\n cached-secrets = ${?OTOROSHI_VAULTS_CACHED_SECRETS}\n read-ttl = 10000 # 10 seconds\n read-ttl = ${?OTOROSHI_VAULTS_READ_TTL}\n # if enabled, only leader nodes fetches the secrets.\n # entities with secret values filled are then sent to workers when they poll the cluster state.\n # only works if `otoroshi.cluster.autoUpdateState=true`\n leader-fetch-only = false\n leader-fetch-only = ${?OTOROSHI_VAULTS_LEADER_FETCH_ONLY}\n env {\n type = \"env\"\n prefix = ${?OTOROSHI_VAULTS_ENV_PREFIX}\n }\n}\n```\n\nyou can see here the global configuration and a default backend configured that can retrieve secrets from environment variables. \n\nThe configuration keys can be used for \n\n- `secrets-ttl`: the amount of milliseconds for a secret to be cached\n- `cached-secrets`: the number of secrets that will be cached on an otoroshi instance\n- `read-ttl`: the timeout (in milliseconds) to read a secret from a backend\n\n## Entities with secrets management\n\nthe entities that support secrets management are the following \n\n- `routes`\n- `services`\n- `service_descriptors`\n- `apikeys`\n- `certificates`\n- `jwt_verifiers`\n- `authentication_modules`\n- `targets`\n- `backends`\n- `tcp_services`\n- `data_exporters`\n\n## Define a reference to a secret\n\nin the previously listed entities, you can define, almost everywhere, references to a secret using the following syntax:\n\n`${vault://name_of_the_vault/secret/of/the/path}`\n\nlet say I define a new apikey with the following value as secret `${vault://my_env/apikey_secret}` with the following secrets management configuration\n\n```conf\nvaults {\n enabled = true\n secrets-ttl = 300000\n cached-secrets = 10000\n read-ttl = 10000\n my_env {\n type = \"env\"\n }\n}\n```\n\nif the machine running otoroshi has an environment variable named `APIKEY_SECRET` with the value `verysecret`, then you will be able to can an api with the defined apikey `client_id` and a `client_secret` value of `verysecret`\n\n```sh\ncurl 'http://my-awesome-api.oto.tools:8080/api/stuff' -u awesome_apikey:verysecret\n```\n\n## Possible backends\n\nOtoroshi comes with the support of several secrets management backends.\n\n### Environment variables\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"env\"\n prefix = \"the_prefix_added_to_the_name_of_the_env_variable\"\n }\n}\n```\n\n### Hashicorp Vault\n\na backend for [Hashicorp Vault](https://www.vaultproject.io/). Right now we only support KV engines.\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"hashicorp-vault\"\n url = \"http://127.0.0.1:8200\"\n mount = \"kv\" # the name of the secret store in vault\n kv = \"v2\" # the version of the kv store (v1 or v2)\n token = \"root\" # the token that can access to your secrets\n }\n}\n```\n\nyou should define your references like `${vault://hashicorp_vault/secret/path/key_name}`.\n\n\n### Azure Key Vault\n\na backend for [Azure Key Vault](https://azure.microsoft.com/en-en/services/key-vault/). Right now we only support secrets and not keys and certificates.\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"azure\"\n url = \"https://keyvaultname.vault.azure.net\"\n api-version = \"7.2\" # the api version of the vault\n tenant = \"xxxx-xxx-xxx\" # your azure tenant id, optional\n client_id = \"xxxxx\" # your azure client_id\n client_secret = \"xxxxx\" # your azure client_secret\n # token = \"xxx\" possible if you have a long lived existing token. will take over tenant / client_id / client_secret\n }\n}\n```\n\nyou should define your references like `${vault://azure_vault/secret_name/secret_version}`. `secret_version` is mandatory\n\n### AWS Secrets Manager\n\na backend for [AWS Secrets Manager](https://aws.amazon.com/en/secrets-manager/)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"aws\"\n access-key = \"key\"\n access-key-secret = \"secret\"\n region = \"eu-west-3\" # the aws region of your secrets management\n }\n}\n```\n\nyou should define your references like `${vault://aws_vault/secret_name/secret_version}`. `secret_version` is optional\n\n### Google Cloud Secrets Manager\n\na backend for [Google Cloud Secrets Manager](https://cloud.google.com/secret-manager)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"gcloud\"\n url = \"https://secretmanager.googleapis.com\"\n apikey = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://gcloud_vault/projects/foo/secrets/bar/versions/the_version}`. `the_version` can be `latest`\n\n### AlibabaCloud Cloud Secrets Manager\n\na backend for [AlibabaCloud Secrets Manager](https://www.alibabacloud.com/help/en/doc-detail/152001.html)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"alibaba-cloud\"\n url = \"https://kms.eu-central-1.aliyuncs.com\"\n access-key-id = \"access-key\"\n access-key-secret = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://alibaba_vault/secret_name}`\n\n\n### Kubernetes Secrets\n\na backend for [Kubernetes secrets](https://kubernetes.io/en/docs/concepts/configuration/secret/)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"kubernetes\"\n # see the configuration of the kubernetes plugin, \n # by default if the pod if well configured, \n # you don't have to setup anything\n }\n}\n```\n\nyou should define your references like `${vault://k8s_vault/namespace/secret_name/key_name}`. `key_name` is optional. if present, otoroshi will try to lookup `key_name` in the secrets `stringData`, if not defined the secrets `data` will be base64 decoded and used.\n\n\n### Izanami config.\n\na backend for [Izanami config.](https://maif.github.io/izanami/manual/)\n\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"izanami\"\n url = \"http://127.0.0.1:8200\"\n client-id = \"client\"\n client-secret = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://izanami_vault/the:secret:id/key_name}`. `key_name` is optional if the secret value is not a json object" - }, - { - "name": "built-in-plugins.md", - "id": "/plugins/built-in-plugins.md", - "url": "/plugins/built-in-plugins.html", - "title": "Otoroshi built-in plugins", - "content": "# Otoroshi built-in plugins\n\nOtoroshi provides some plugins out of the box. Here is the available plugins with their documentation and reference configuration\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.AccessLog }\n\n## Access log (CLF)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `AccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged in CLF format.\n\nLog format is the following:\n\n`\"$service\" $clientAddress - \"$userId\" [$timestamp] \"$host $method $path $protocol\" \"$status $statusTxt\" $size $snowflake \"$to\" \"$referer\" \"$userAgent\" $http $duration $errorMsg`\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"AccessLog\": {\n \"enabled\": true,\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"AccessLog\" : {\n \"enabled\" : true,\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.AccessLogJson }\n\n## Access log (JSON)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `AccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged in json format.\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"AccessLog\": {\n \"enabled\": true,\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"AccessLog\" : {\n \"enabled\" : true,\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.KafkaAccessLog }\n\n## Kafka access log\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `KafkaAccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged as an event in a kafka topic.\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"KafkaAccessLog\": {\n \"enabled\": true,\n \"topic\": \"otoroshi-access-log\",\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KafkaAccessLog\" : {\n \"enabled\" : true,\n \"topic\" : \"otoroshi-access-log\",\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.authcallers.BasicAuthCaller }\n\n## Basic Auth. caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `BasicAuthCaller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using basic auth.\n\nThis plugin accepts the following configuration\n\n{\n \"username\" : \"the_username\",\n \"password\" : \"the_password\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Basic %s\"\n}\n\n\n\n### Default configuration\n\n```json\n{\n \"username\" : \"the_username\",\n \"password\" : \"the_password\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Basic %s\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.authcallers.OAuth2Caller }\n\n## OAuth2 caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OAuth2Caller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using OAuth2 client_credential/password flow.\nDo not forget to enable client retry to handle token generation on expire.\n\nThis plugin accepts the following configuration\n\n{\n \"kind\" : \"the oauth2 flow, can be 'client_credentials' or 'password'\",\n \"url\" : \"https://127.0.0.1:8080/oauth/token\",\n \"method\" : \"POST\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Bearer %s\",\n \"jsonPayload\" : false,\n \"clientId\" : \"the client_id\",\n \"clientSecret\" : \"the client_secret\",\n \"scope\" : \"an optional scope\",\n \"audience\" : \"an optional audience\",\n \"user\" : \"an optional username if using password flow\",\n \"password\" : \"an optional password if using password flow\",\n \"cacheTokenSeconds\" : \"the number of second to wait before asking for a new token\",\n \"tlsConfig\" : \"an optional TLS settings object\"\n}\n\n\n\n### Default configuration\n\n```json\n{\n \"kind\" : \"the oauth2 flow, can be 'client_credentials' or 'password'\",\n \"url\" : \"https://127.0.0.1:8080/oauth/token\",\n \"method\" : \"POST\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Bearer %s\",\n \"jsonPayload\" : false,\n \"clientId\" : \"the client_id\",\n \"clientSecret\" : \"the client_secret\",\n \"scope\" : \"an optional scope\",\n \"audience\" : \"an optional audience\",\n \"user\" : \"an optional username if using password flow\",\n \"password\" : \"an optional password if using password flow\",\n \"cacheTokenSeconds\" : \"the number of second to wait before asking for a new token\",\n \"tlsConfig\" : \"an optional TLS settings object\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.cache.ResponseCache }\n\n## Response Cache\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ResponseCache`\n\n### Description\n\nThis plugin can cache responses from target services in the otoroshi datasstore\nIt also provides a debug UI at `/.well-known/otoroshi/bodylogger`.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ResponseCache\": {\n \"enabled\": true, // enabled cache\n \"ttl\": 300000, // store it for some times (5 minutes by default)\n \"maxSize\": 5242880, // max body size (body will be cut after that)\n \"autoClean\": true, // cleanup older keys when all bigger than maxSize\n \"filter\": { // cache only for some status, method and paths\n \"statuses\": [],\n \"methods\": [],\n \"paths\": [],\n \"not\": {\n \"statuses\": [],\n \"methods\": [],\n \"paths\": []\n }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ResponseCache\" : {\n \"enabled\" : true,\n \"ttl\" : 3600000,\n \"maxSize\" : 52428800,\n \"autoClean\" : true,\n \"filter\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ],\n \"not\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ]\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.clientcert.ClientCertChainHeader }\n\n## Client certificate header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ClientCertChain`\n\n### Description\n\nThis plugin pass client certificate informations to the target in headers.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ClientCertChain\": {\n \"pem\": { // send client cert as PEM format in a header\n \"send\": false,\n \"header\": \"X-Client-Cert-Pem\"\n },\n \"dns\": { // send JSON array of DNs in a header\n \"send\": false,\n \"header\": \"X-Client-Cert-DNs\"\n },\n \"chain\": { // send JSON representation of client cert chain in a header\n \"send\": true,\n \"header\": \"X-Client-Cert-Chain\"\n },\n \"claims\": { // pass JSON representation of client cert chain in the otoroshi JWT token\n \"send\": false,\n \"name\": \"clientCertChain\"\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ClientCertChain\" : {\n \"pem\" : {\n \"send\" : false,\n \"header\" : \"X-Client-Cert-Pem\"\n },\n \"dns\" : {\n \"send\" : false,\n \"header\" : \"X-Client-Cert-DNs\"\n },\n \"chain\" : {\n \"send\" : true,\n \"header\" : \"X-Client-Cert-Chain\"\n },\n \"claims\" : {\n \"send\" : false,\n \"name\" : \"clientCertChain\"\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.defer.DeferPlugin }\n\n## Defer Responses\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `DeferPlugin`\n\n### Description\n\nThis plugin will expect a `X-Defer` header or a `defer` query param and defer the response according to the value in milliseconds.\nThis plugin is some kind of inside joke as one a our customer ask us to make slower apis.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"DeferPlugin\": {\n \"defaultDefer\": 0 // default defer in millis\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"DeferPlugin\" : {\n \"defaultDefer\" : 0\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.discovery.DiscoverySelfRegistrationTransformer }\n\n## Self registration endpoints (service discovery)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin add support for self registration endpoint on a specific service.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.envoy.EnvoyControlPlane }\n\n## Envoy Control Plane (experimental)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `EnvoyControlPlane`\n\n### Description\n\nThis plugin will expose the otoroshi state to envoy instances using the xDS V3 API`.\n\nRight now, all the features of otoroshi cannot be exposed as is through Envoy.\n\n\n\n### Default configuration\n\n```json\n{\n \"EnvoyControlPlane\" : {\n \"enabled\" : true\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.geoloc.GeolocationInfoEndpoint }\n\n## Geolocation endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: ``none``\n\n### Description\n\nThis plugin will expose current geolocation informations on the following endpoint.\n\n`/.well-known/otoroshi/plugins/geolocation`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.geoloc.GeolocationInfoHeader }\n\n## Geolocation header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `GeolocationInfoHeader`\n\n### Description\n\nThis plugin will send informations extracted by the Geolocation details extractor to the target service in a header.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfoHeader\": {\n \"headerName\": \"X-Geolocation-Info\" // header in which info will be sent\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfoHeader\" : {\n \"headerName\" : \"X-Geolocation-Info\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.hmac.HMACCallerPlugin }\n\n## HMAC caller plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `HMACCallerPlugin`\n\n### Description\n\nThis plugin can be used to call a \"protected\" api by an HMAC signature. It will adds a signature with the secret configured on the plugin.\n The signature string will always the content of the header list listed in the plugin configuration.\n\n\n\n### Default configuration\n\n```json\n{\n \"HMACCallerPlugin\" : {\n \"secret\" : \"my-defaut-secret\",\n \"algo\" : \"HMAC-SHA512\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.izanami.IzanamiCanary }\n\n## Izanami Canary Campaign\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `IzanamiCanary`\n\n### Description\n\nThis plugin allow you to perform canary testing based on an izanami experiment campaign (A/B test).\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"IzanamiCanary\" : {\n \"experimentId\" : \"foo:bar:qix\",\n \"configId\" : \"foo:bar:qix:config\",\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000,\n \"mtls\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"IzanamiCanary\" : {\n \"experimentId\" : \"foo:bar:qix\",\n \"configId\" : \"foo:bar:qix:config\",\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000,\n \"mtls\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.izanami.IzanamiProxy }\n\n## Izanami APIs Proxy\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `IzanamiProxy`\n\n### Description\n\nThis plugin exposes routes to proxy Izanami configuration and features tree APIs.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"IzanamiProxy\" : {\n \"path\" : \"/api/izanami\",\n \"featurePattern\" : \"*\",\n \"configPattern\" : \"*\",\n \"autoContext\" : false,\n \"featuresEnabled\" : true,\n \"featuresWithContextEnabled\" : true,\n \"configurationEnabled\" : false,\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"IzanamiProxy\" : {\n \"path\" : \"/api/izanami\",\n \"featurePattern\" : \"*\",\n \"configPattern\" : \"*\",\n \"autoContext\" : false,\n \"featuresEnabled\" : true,\n \"featuresWithContextEnabled\" : true,\n \"configurationEnabled\" : false,\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.jq.JqBodyTransformer }\n\n## JQ bodies transformer\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `JqBodyTransformer`\n\n### Description\n\nThis plugin let you transform JSON bodies (in requests and responses) using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\nSome JSON variables are accessible by default :\n\n * `$url`: the request url\n * `$path`: the request path\n * `$domain`: the request domain\n * `$method`: the request method\n * `$headers`: the current request headers (with name in lowercase)\n * `$queryParams`: the current request query params\n * `$otoToken`: the otoroshi protocol token (if one)\n * `$inToken`: the first matched JWT token as is (from verifiers, if one)\n * `$token`: the first matched JWT token as is (from verifiers, if one)\n * `$user`: the current user (if one)\n * `$apikey`: the current apikey (if one)\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"JqBodyTransformer\" : {\n \"request\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n },\n \"response\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"JqBodyTransformer\" : {\n \"request\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n },\n \"response\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.jsoup.HtmlPatcher }\n\n## Html Patcher\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `HtmlPatcher`\n\n### Description\n\nThis plugin can inject elements in html pages (in the body or in the head) returned by the service\n\n\n\n### Default configuration\n\n```json\n{\n \"HtmlPatcher\" : {\n \"appendHead\" : [ ],\n \"appendBody\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.log4j.Log4ShellFilter }\n\n## Log4Shell mitigation plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `Log4ShellFilter`\n\n### Description\n\nThis plugin try to detect Log4Shell attacks in request and block them.\n\nThis plugin can accept the following configuration\n\n```javascript\n{\n \"Log4ShellFilter\": {\n \"status\": 200, // the status send back when an attack expression is found\n \"body\": \"\", // the body send back when an attack expression is found\n \"parseBody\": false // enables request body parsing to find attack expression\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"Log4ShellFilter\" : {\n \"status\" : 200,\n \"body\" : \"\",\n \"parseBody\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.loggers.BodyLogger }\n\n## Body logger\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `BodyLogger`\n\n### Description\n\nThis plugin can log body present in request and response. It can just logs it, store in in the redis store with a ttl and send it to analytics.\nIt also provides a debug UI at `/.well-known/otoroshi/bodylogger`.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"BodyLogger\": {\n \"enabled\": true, // enabled logging\n \"log\": true, // just log it\n \"store\": false, // store bodies in datastore\n \"ttl\": 300000, // store it for some times (5 minutes by default)\n \"sendToAnalytics\": false, // send bodies to analytics\n \"maxSize\": 5242880, // max body size (body will be cut after that)\n \"password\": \"password\", // password for the ui, if none, it's public\n \"filter\": { // log only for some status, method and paths\n \"statuses\": [],\n \"methods\": [],\n \"paths\": [],\n \"not\": {\n \"statuses\": [],\n \"methods\": [],\n \"paths\": []\n }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"BodyLogger\" : {\n \"enabled\" : true,\n \"log\" : true,\n \"store\" : false,\n \"ttl\" : 300000,\n \"sendToAnalytics\" : false,\n \"maxSize\" : 5242880,\n \"password\" : \"password\",\n \"filter\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ],\n \"not\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ]\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.metrics.PrometheusServiceMetrics }\n\n## Prometheus Service Metrics\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `PrometheusServiceMetrics`\n\n### Description\n\nThis plugin collects service metrics and can be used with the `Prometheus Endpoint` (in the Danger Zone) plugin to expose those metrics\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"PrometheusServiceMetrics\": {\n \"includeUri\": false // include http uri in metrics. WARNING this could impliess performance issues, use at your own risks\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"PrometheusServiceMetrics\" : {\n \"includeUri\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.metrics.ServiceMetrics }\n\n## Service Metrics\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ServiceMetrics`\n\n### Description\n\nThis plugin expose service metrics in Otoroshi global metrics or on a special URL of the service `/.well-known/otoroshi/metrics`.\nMetrics are exposed in json or prometheus format depending on the accept header. You can protect it with an access key defined in the configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ServiceMetrics\": {\n \"accessKeyValue\": \"secret\", // if not defined, public access. Can be ${config.app.health.accessKey}\n \"accessKeyQuery\": \"access_key\"\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ServiceMetrics\" : {\n \"accessKeyValue\" : \"${config.app.health.accessKey}\",\n \"accessKeyQuery\" : \"access_key\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.mirror.MirroringPlugin }\n\n## Mirroring plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `MirroringPlugin`\n\n### Description\n\nThis plugin will mirror every request to other targets\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"MirroringPlugin\": {\n \"enabled\": true, // enabled mirroring\n \"to\": \"https://foo.bar.dev\", // the url of the service to mirror\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"MirroringPlugin\" : {\n \"enabled\" : true,\n \"to\" : \"https://foo.bar.dev\",\n \"captureResponse\" : false,\n \"generateEvents\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.oauth1.OAuth1CallerPlugin }\n\n## OAuth1 caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OAuth1Caller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using OAuth1.\n Consumer key, secret, and OAuth token et OAuth token secret can be pass through the metadata of an api key\n or via the configuration of this plugin.\n\n\n\n### Default configuration\n\n```json\n{\n \"OAuth1Caller\" : {\n \"algo\" : \"HmacSHA512\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.oidc.OIDCHeaders }\n\n## OIDC headers\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OIDCHeaders`\n\n### Description\n\nThis plugin injects headers containing tokens and profile from current OIDC provider.\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCHeaders\" : {\n \"profile\" : {\n \"send\" : true,\n \"headerName\" : \"X-OIDC-User\"\n },\n \"idtoken\" : {\n \"send\" : false,\n \"name\" : \"id_token\",\n \"headerName\" : \"X-OIDC-Id-Token\",\n \"jwt\" : true\n },\n \"accesstoken\" : {\n \"send\" : false,\n \"name\" : \"access_token\",\n \"headerName\" : \"X-OIDC-Access-Token\",\n \"jwt\" : true\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.security.SecurityTxt }\n\n## Security Txt\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `SecurityTxt`\n\n### Description\n\nThis plugin exposes a special route `/.well-known/security.txt` as proposed at [https://securitytxt.org/](https://securitytxt.org/).\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"SecurityTxt\": {\n \"Contact\": \"contact@foo.bar\", // mandatory, a link or e-mail address for people to contact you about security issues\n \"Encryption\": \"http://url-to-public-key\", // optional, a link to a key which security researchers should use to securely talk to you\n \"Acknowledgments\": \"http://url\", // optional, a link to a web page where you say thank you to security researchers who have helped you\n \"Preferred-Languages\": \"en, fr, es\", // optional\n \"Policy\": \"http://url\", // optional, a link to a policy detailing what security researchers should do when searching for or reporting security issues\n \"Hiring\": \"http://url\", // optional, a link to any security-related job openings in your organisation\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"SecurityTxt\" : {\n \"Contact\" : \"contact@foo.bar\",\n \"Encryption\" : \"https://...\",\n \"Acknowledgments\" : \"https://...\",\n \"Preferred-Languages\" : \"en, fr\",\n \"Policy\" : \"https://...\",\n \"Hiring\" : \"https://...\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.static.StaticResponse }\n\n## Static Response\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `StaticResponse`\n\n### Description\n\nThis plugin returns a static response for any request\n\n\n\n### Default configuration\n\n```json\n{\n \"StaticResponse\" : {\n \"status\" : 200,\n \"headers\" : {\n \"Content-Type\" : \"application/json\"\n },\n \"body\" : \"{\\\"message\\\":\\\"hello world!\\\"}\",\n \"bodyBase64\" : null\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.useragent.UserAgentInfoEndpoint }\n\n## User-Agent endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: ``none``\n\n### Description\n\nThis plugin will expose current user-agent informations on the following endpoint.\n\n`/.well-known/otoroshi/plugins/user-agent`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.useragent.UserAgentInfoHeader }\n\n## User-Agent header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `UserAgentInfoHeader`\n\n### Description\n\nThis plugin will sent informations extracted by the User-Agent details extractor to the target service in a header.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"UserAgentInfoHeader\": {\n \"headerName\": \"X-User-Agent-Info\" // header in which info will be sent\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"UserAgentInfoHeader\" : {\n \"headerName\" : \"X-User-Agent-Info\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.workflow.WorkflowEndpoint }\n\n## Workflow endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `WorkflowEndpoint`\n\n### Description\n\nThis plugin runs a workflow and return the response\n\n\n\n### Default configuration\n\n```json\n{\n \"WorkflowEndpoint\" : {\n \"workflow\" : { }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.biscuit.BiscuitValidator }\n\n## Biscuit token validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nThis plugin validates a Biscuit token.\n\n\n\n### Default configuration\n\n```json\n{\n \"publicKey\" : \"xxxxxx\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingApikeyValidator }\n\n## Client Certificate + Api Key only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nCheck if a client certificate is present in the request and that the apikey used matches the client certificate.\nYou can set the client cert. DN in an apikey metadata named `allowed-client-cert-dn`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingHttpValidator }\n\n## Client certificate matching (over http)\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasClientCertMatchingHttpValidator`\n\n### Description\n\nCheck if client certificate matches the following configuration\n\nexpected response from http service is\n\n```json\n{\n \"serialNumbers\": [], // allowed certificated serial numbers\n \"subjectDNs\": [], // allowed certificated DNs\n \"issuerDNs\": [], // allowed certificated issuer DNs\n \"regexSubjectDNs\": [], // allowed certificated DNs matching regex\n \"regexIssuerDNs\": [], // allowed certificated issuer DNs matching regex\n}\n```\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"url\": \"...\", // url for the call\n \"headers\": {}, // http header for the call\n \"ttl\": 600000, // cache ttl,\n \"mtlsConfig\": {\n \"certId\": \"xxxxx\",\n \"mtls\": false,\n \"loose\": false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasClientCertMatchingHttpValidator\" : {\n \"url\" : \"http://foo.bar\",\n \"ttl\" : 600000,\n \"headers\" : { },\n \"mtlsConfig\" : {\n \"certId\" : \"...\",\n \"mtls\" : false,\n \"loose\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingValidator }\n\n## Client certificate matching\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasClientCertMatchingValidator`\n\n### Description\n\nCheck if client certificate matches the following configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"serialNumbers\": [], // allowed certificated serial numbers\n \"subjectDNs\": [], // allowed certificated DNs\n \"issuerDNs\": [], // allowed certificated issuer DNs\n \"regexSubjectDNs\": [], // allowed certificated DNs matching regex\n \"regexIssuerDNs\": [], // allowed certificated issuer DNs matching regex\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\" : {\n \"serialNumbers\" : [ ],\n \"subjectDNs\" : [ ],\n \"issuerDNs\" : [ ],\n \"regexSubjectDNs\" : [ ],\n \"regexIssuerDNs\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertValidator }\n\n## Client Certificate Only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nCheck if a client certificate is present in the request\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.external.ExternalHttpValidator }\n\n## External Http Validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `ExternalHttpValidator`\n\n### Description\n\nCalls an external http service to know if a user has access or not. Uses cache for performances.\n\nThe sent payload is the following:\n\n```json\n{\n \"apikey\": {...},\n \"user\": {...},\n \"service\": : {...},\n \"chain\": \"...\", // PEM cert chain\n \"fingerprints\": [...]\n}\n```\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ExternalHttpValidator\": {\n \"url\": \"...\", // url for the http call\n \"host\": \"...\", // value of the host header for the call. default is host of the url\n \"goodTtl\": 600000, // ttl in ms for a validated call\n \"badTtl\": 60000, // ttl in ms for a not validated call\n \"method\": \"POST\", // http methode\n \"path\": \"/certificates/_validate\", // http uri path\n \"timeout\": 10000, // http call timeout\n \"noCache\": false, // use cache or not\n \"allowNoClientCert\": false, //\n \"headers\": {}, // headers for the http call if needed\n \"mtlsConfig\": {\n \"certId\": \"xxxxx\",\n \"mtls\": false,\n \"loose\": false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ExternalHttpValidator\" : {\n \"url\" : \"http://foo.bar\",\n \"host\" : \"api.foo.bar\",\n \"goodTtl\" : 600000,\n \"badTtl\" : 60000,\n \"method\" : \"POST\",\n \"path\" : \"/certificates/_validate\",\n \"timeout\" : 10000,\n \"noCache\" : false,\n \"allowNoClientCert\" : false,\n \"headers\" : { },\n \"mtlsConfig\" : {\n \"certId\" : \"...\",\n \"mtls\" : false,\n \"loose\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.hmac.HMACValidator }\n\n## HMAC access validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HMACAccessValidator`\n\n### Description\n\nThis plugin can be used to check if a HMAC signature is present and valid in Authorization header.\n\n\n\n### Default configuration\n\n```json\n{\n \"HMACAccessValidator\" : {\n \"secret\" : \"\"\n }\n}\n```\n\n\n\n### Documentation\n\n\n The HMAC signature needs to be set on the `Authorization` or `Proxy-Authorization` header.\n The format of this header should be : `hmac algorithm=\"\", headers=\"
\", signature=\"\"`\n As example, a simple nodeJS call with the expected header\n ```js\n const crypto = require('crypto');\n const fetch = require('node-fetch');\n\n const date = new Date()\n const secret = \"my-secret\" // equal to the api key secret by default\n\n const algo = \"sha512\"\n const signature = crypto.createHmac(algo, secret)\n .update(date.getTime().toString())\n .digest('base64');\n\n fetch('http://myservice.oto.tools:9999/api/test', {\n headers: {\n \"Otoroshi-Client-Id\": \"my-id\",\n \"Otoroshi-Client-Secret\": \"my-secret\",\n \"Date\": date.getTime().toString(),\n \"Authorization\": `hmac algorithm=\"hmac-${algo}\", headers=\"Date\", signature=\"${signature}\"`,\n \"Accept\": \"application/json\"\n }\n })\n .then(r => r.json())\n .then(console.log)\n ```\n In this example, we have an Otoroshi service deployed on http://myservice.oto.tools:9999/api/test, protected by api keys.\n The secret used is the secret of the api key (by default, but you can change it and define a secret on the plugin configuration).\n We send the base64 encoded date of the day, signed by the secret, in the Authorization header. We specify the headers signed and the type of algorithm used.\n You can sign more than one header but you have to list them in the headers fields (each one separate by a space, example : headers=\"Date KeyId\").\n The algorithm used can be HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 or HMAC-SHA512.\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.oidc.OIDCAccessTokenValidator }\n\n## OIDC access_token validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `OIDCAccessTokenValidator`\n\n### Description\n\nThis plugin will use the third party apikey configuration and apply it while keeping the apikey mecanism of otoroshi.\nUse it to combine apikey validation and OIDC access_token validation.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\": {\n \"enabled\": true,\n \"atLeastOne\": false,\n // config is optional and can be either an object config or an array of objects\n \"config\": {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n}\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\" : {\n \"enabled\" : true,\n \"atLeastOne\" : false,\n \"config\" : {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.quotas.InstanceQuotas }\n\n## Instance quotas\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `InstanceQuotas`\n\n### Description\n\nThis plugin will enforce global quotas on the current instance\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"InstanceQuotas\": {\n \"callsPerDay\": -1, // max allowed api calls per day\n \"callsPerMonth\": -1, // max allowed api calls per month\n \"maxDescriptors\": -1, // max allowed service descriptors\n \"maxApiKeys\": -1, // max allowed apikeys\n \"maxGroups\": -1, // max allowed service groups\n \"maxScripts\": -1, // max allowed apikeys\n \"maxCertificates\": -1, // max allowed certificates\n \"maxVerifiers\": -1, // max allowed jwt verifiers\n \"maxAuthModules\": -1, // max allowed auth modules\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"InstanceQuotas\" : {\n \"callsPerDay\" : -1,\n \"callsPerMonth\" : -1,\n \"maxDescriptors\" : -1,\n \"maxApiKeys\" : -1,\n \"maxGroups\" : -1,\n \"maxScripts\" : -1,\n \"maxCertificates\" : -1,\n \"maxVerifiers\" : -1,\n \"maxAuthModules\" : -1\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.quotas.ServiceQuotas }\n\n## Public quotas\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `ServiceQuotas`\n\n### Description\n\nThis plugin will enforce public quotas on the current service\n\n\n\n\n\n\n\n### Default configuration\n\n```json\n{\n \"ServiceQuotas\" : {\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.users.HasAllowedUsersValidator }\n\n## Allowed users only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasAllowedUsersValidator`\n\n### Description\n\nThis plugin only let allowed users pass\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasAllowedUsersValidator\": {\n \"usernames\": [], // allowed usernames\n \"emails\": [], // allowed user email addresses\n \"emailDomains\": [], // allowed user email domains\n \"metadataMatch\": [], // json path expressions to match against user metadata. passes if one match\n \"metadataNotMatch\": [], // json path expressions to match against user metadata. passes if none match\n \"profileMatch\": [], // json path expressions to match against user profile. passes if one match\n \"profileNotMatch\": [], // json path expressions to match against user profile. passes if none match\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasAllowedUsersValidator\" : {\n \"usernames\" : [ ],\n \"emails\" : [ ],\n \"emailDomains\" : [ ],\n \"metadataMatch\" : [ ],\n \"metadataNotMatch\" : [ ],\n \"profileMatch\" : [ ],\n \"profileNotMatch\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.ApikeyAuthModule }\n\n## Apikey auth module\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `ApikeyAuthModule`\n\n### Description\n\nThis plugin adds basic auth on service where credentials are valid apikeys on the current service.\n\n\n\n### Default configuration\n\n```json\n{\n \"ApikeyAuthModule\" : {\n \"realm\" : \"apikey-auth-module-realm\",\n \"noneTagIn\" : [ ],\n \"oneTagIn\" : [ ],\n \"allTagsIn\" : [ ],\n \"noneMetaIn\" : [ ],\n \"oneMetaIn\" : [ ],\n \"allMetaIn\" : [ ],\n \"noneMetaKeysIn\" : [ ],\n \"oneMetaKeyIn\" : [ ],\n \"allMetaKeysIn\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.CertificateAsApikey }\n\n## Client certificate as apikey\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `CertificateAsApikey`\n\n### Description\n\nThis plugin uses client certificate as an apikey. The apikey will be stored for classic apikey usage\n\n\n\n### Default configuration\n\n```json\n{\n \"CertificateAsApikey\" : {\n \"readOnly\" : false,\n \"allowClientIdOnly\" : false,\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"constrainedServicesOnly\" : false,\n \"tags\" : [ ],\n \"metadata\" : { }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.ClientCredentialFlowExtractor }\n\n## Client Credential Flow ApiKey extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: ``none``\n\n### Description\n\nThis plugin can extract an apikey from an opaque access_token generate by the `ClientCredentialFlow` plugin\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.biscuit.BiscuitExtractor }\n\n## Apikey from Biscuit token extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: ``none``\n\n### Description\n\nThis plugin extract an from a Biscuit token where the biscuit has an #authority fact 'client_id' containing\napikey client_id and an #authority fact 'client_sign' that is the HMAC256 signature of the apikey client_id with the apikey client_secret\n\n\n\n### Default configuration\n\n```json\n{\n \"publicKey\" : \"xxxxxx\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.discovery.DiscoveryTargetsSelector }\n\n## Service discovery target selector (service discovery)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin select a target in the pool of discovered targets for this service.\nUse in combination with either `DiscoverySelfRegistrationSink` or `DiscoverySelfRegistrationTransformer` to make it work using the `self registration` pattern.\nOr use an implementation of `DiscoveryJob` for the `third party registration pattern`.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.geoloc.IpStackGeolocationInfoExtractor }\n\n## Geolocation details extractor (using IpStack api)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `GeolocationInfo`\n\n### Description\n\nThis plugin extract geolocation informations from ip address using the [IpStack dbs](https://ipstack.com/).\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfo\": {\n \"apikey\": \"xxxxxxx\",\n \"timeout\": 2000, // timeout in ms\n \"log\": false // will log geolocation details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfo\" : {\n \"apikey\" : \"xxxxxxx\",\n \"timeout\" : 2000,\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.geoloc.MaxMindGeolocationInfoExtractor }\n\n## Geolocation details extractor (using Maxmind db)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `GeolocationInfo`\n\n### Description\n\nThis plugin extract geolocation informations from ip address using the [Maxmind dbs](https://www.maxmind.com/en/geoip2-databases).\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfo\": {\n \"path\": \"/foo/bar/cities.mmdb\", // file path, can be \"global\"\n \"log\": false // will log geolocation details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfo\" : {\n \"path\" : \"global\",\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.jwt.JwtUserExtractor }\n\n## Jwt user extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `JwtUserExtractor`\n\n### Description\n\nThis plugin extract a user from a JWT token\n\n\n\n### Default configuration\n\n```json\n{\n \"JwtUserExtractor\" : {\n \"verifier\" : \"\",\n \"strict\" : true,\n \"namePath\" : \"name\",\n \"emailPath\" : \"email\",\n \"metaPath\" : null\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.oidc.OIDCAccessTokenAsApikey }\n\n## OIDC access_token as apikey\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `OIDCAccessTokenAsApikey`\n\n### Description\n\nThis plugin will use the third party apikey configuration to generate an apikey\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\": {\n \"enabled\": true,\n \"atLeastOne\": false,\n // config is optional and can be either an object config or an array of objects\n \"config\": {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n}\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCAccessTokenAsApikey\" : {\n \"enabled\" : true,\n \"atLeastOne\" : false,\n \"config\" : {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.useragent.UserAgentExtractor }\n\n## User-Agent details extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `UserAgentInfo`\n\n### Description\n\nThis plugin extract informations from User-Agent header such as browsser version, OS version, etc.\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"UserAgentInfo\": {\n \"log\": false // will log user-agent details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"UserAgentInfo\" : {\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.apikeys.ClientCredentialService }\n\n## Client Credential Service\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `ClientCredentialService`\n\n### Description\n\nThis plugin add an an oauth client credentials service (`https://unhandleddomain/.well-known/otoroshi/oauth/token`) to create an access_token given a client id and secret.\n\n```json\n{\n \"ClientCredentialService\" : {\n \"domain\" : \"*\",\n \"expiration\" : 3600000,\n \"defaultKeyPair\" : \"otoroshi-jwt-signing\",\n \"secure\" : true\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ClientCredentialService\" : {\n \"domain\" : \"*\",\n \"expiration\" : 3600000,\n \"defaultKeyPair\" : \"otoroshi-jwt-signing\",\n \"secure\" : true\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.discovery.DiscoverySelfRegistrationSink }\n\n## Global self registration endpoints (service discovery)\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin add support for self registration endpoint on specific hostnames.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator }\n\n## Kubernetes admission validator webhook\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: ``none``\n\n### Description\n\nThis plugin exposes a webhook to kubernetes to handle manifests validation\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector }\n\n## Kubernetes sidecar injector webhook\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: ``none``\n\n### Description\n\nThis plugin exposes a webhook to kubernetes to inject otoroshi-sidecar in pods\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.metrics.PrometheusEndpoint }\n\n## Prometheus Endpoint\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `PrometheusEndpoint`\n\n### Description\n\nThis plugin exposes metrics collected by `Prometheus Service Metrics` on a `/prometheus` endpoint.\nYou can protect it with an access key defined in the configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"PrometheusEndpoint\": {\n \"accessKeyValue\": \"secret\", // if not defined, public access. Can be ${config.app.health.accessKey}\n \"accessKeyQuery\": \"access_key\",\n \"includeMetrics\": false\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"PrometheusEndpoint\" : {\n \"accessKeyValue\" : \"${config.app.health.accessKey}\",\n \"accessKeyQuery\" : \"access_key\",\n \"includeMetrics\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesIngressControllerJob }\n\n## Kubernetes Ingress Controller\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin enables Otoroshi as an Ingress Controller\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob }\n\n## Kubernetes Otoroshi CRDs Controller\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin enables Otoroshi CRDs Controller\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesToOtoroshiCertSyncJob }\n\n## Kubernetes to Otoroshi certs. synchronizer\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin syncs. TLS secrets from Kubernetes to Otoroshi\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.OtoroshiToKubernetesCertSyncJob }\n\n## Otoroshi certs. to Kubernetes secrets synchronizer\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin syncs. Otoroshi certs to Kubernetes TLS secrets\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.workflow.WorkflowJob }\n\n## Workflow job\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `WorkflowJob`\n\n### Description\n\nPeriodically run a custom workflow\n\n\n\n### Default configuration\n\n```json\n{\n \"WorkflowJob\" : {\n \"input\" : {\n \"namespace\" : \"otoroshi\",\n \"service\" : \"otoroshi-dns\"\n },\n \"intervalMillis\" : \"60000\",\n \"workflow\" : {\n \"name\" : \"some-workflow\",\n \"description\" : \"a nice workflow\",\n \"tasks\" : [ {\n \"name\" : \"call-dns\",\n \"type\" : \"http\",\n \"request\" : {\n \"method\" : \"PATCH\",\n \"url\" : \"http://${env.KUBERNETES_SERVICE_HOST}:${env.KUBERNETES_SERVICE_PORT}/apis/v1/namespaces/${input.namespace}/services/${input.service}\",\n \"headers\" : {\n \"accept\" : \"application/json\",\n \"content-type\" : \"application/json\",\n \"authorization\" : \"Bearer ${file:///var/run/secrets/kubernetes.io/serviceaccount/token}\"\n },\n \"tls\" : {\n \"mtls\" : true,\n \"trustAll\" : true\n },\n \"body\" : [ {\n \"op\" : \"replace\",\n \"path\" : \"/spec/selector\",\n \"value\" : {\n \"app\" : \"otoroshi\",\n \"component\" : \"dns\"\n }\n } ]\n },\n \"success\" : {\n \"statuses\" : [ 200 ]\n }\n } ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-request-handler #otoroshi.next.proxy.ProxyEngine }\n\n## Otoroshi next proxy engine (experimental)\n\n\n\n### Infos\n\n* plugin type: `request-handler`\n* configuration root: `NextGenProxyEngine`\n\n### Description\n\nThis plugin holds the next generation otoroshi proxy engine implementation. This engine is **experimental** and may not work as expected !\n\nYou can active this plugin only on some domain names so you can easily A/B test the new engine.\nThe new proxy engine is designed to be more reactive and more efficient generally.\nIt is also designed to be very efficient on path routing where it wasn't the old engines strong suit.\n\nThe idea is to only rely on plugins to work and avoid losing time with features that are not used in service descriptors.\nAn automated conversion happens for every service descriptor. If the exposed domain is handled by this plugin, it will be served by this plugin.\nThis plugin introduces new entities that will replace (one day maybe) service descriptors:\n\n - `routes`: a unique routing rule based on hostname, path, method and headers that will execute a bunch of plugins\n - `services`: multiple routing rules based on hostname, path, method and headers that will execute the same list of plugins\n - `targets`: how to contact a backend either by using a domain name or an ip address, supports mtls\n - `backends`: a list of targets to contact a backend\n\nas an example, let say you want to use the new engine on your service exposed on `api.foo.bar/api`.\nTo do that, just add the plugin in the `global plugins` section of the danger zone, inject the default configuration,\nenabled it and in `domains` add the value `api.foo.bar` (it is possible to use `*.foo.bar` if that's what you want to do).\nThe next time a request hits the `api.foo.bar` domain, the new engine will handle it instead of the old one.\n\n\n\n### Default configuration\n\n```json\n{\n \"enabled\" : true,\n \"domains\" : [ \"*-next-gen.oto.tools\" ],\n \"deny_domains\" : [ ],\n \"reporting\" : true,\n \"merge_sync_steps\" : true,\n \"export_reporting\" : false,\n \"apply_legacy_checks\" : true,\n \"debug\" : false,\n \"capture\" : false,\n \"captureMaxEntitySize\" : 4194304,\n \"debug_headers\" : false,\n \"routing_strategy\" : \"tree\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-request-handler #otoroshi.script.ForwardTrafficHandler }\n\n## Forward traffic\n\n\n\n### Infos\n\n* plugin type: `request-handler`\n* configuration root: `ForwardTrafficHandler`\n\n### Description\n\nThis plugin can be use to perform a raw traffic forward to an URL without passing through otoroshi routing\n\n\n\n### Default configuration\n\n```json\n{\n \"ForwardTrafficHandler\" : {\n \"domains\" : {\n \"my.domain.tld\" : {\n \"baseUrl\" : \"https://my.otherdomain.tld\",\n \"secret\" : \"jwt signing secret\",\n \"service\" : {\n \"id\" : \"service id for analytics\",\n \"name\" : \"service name for analytics\"\n }\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n\n\n" - }, - { - "name": "create-plugins.md", - "id": "/plugins/create-plugins.md", - "url": "/plugins/create-plugins.html", - "title": "Create plugins", - "content": "# Create plugins\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated\n@@@\n\nWhen everything has failed and you absolutely need a feature in Otoroshi to make your use case work, there is a solution. Plugins is the feature in Otoroshi that allow you to code how Otoroshi should behave when receiving, validating and routing an http request. With request plugin, you can change request / response headers and request / response body the way you want, provide your own apikey, etc.\n\n## Plugin types\n\nthere are many plugin types explained @ref:[here](./plugins.md) \n\n## Code and signatures\n\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/requestsink.scala#L14-L19\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/routing.scala#L75-L78\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/accessvalidator.scala#L65-L85\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/script.scala#269-L540\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/eventlistener.scala#L27-L48\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/job.scala#L69-L164\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/job.scala#L108-L110\n\n\nfor more information about APIs you can use\n\n* https://www.playframework.com/documentation/2.8.x/api/scala/index.html#package\n* https://www.playframework.com/documentation/2.8.x/api/scala/index.html#play.api.mvc.Results\n* https://github.com/MAIF/otoroshi\n* https://doc.akka.io/docs/akka/2.5/stream/index.html\n* https://doc.akka.io/api/akka/current/akka/stream/index.html\n* https://doc.akka.io/api/akka/current/akka/stream/scaladsl/Source.html\n\n## Plugin examples\n\n@ref:[A lot of plugins](./built-in-plugins.md) comes with otoroshi, you can find them on [github](https://github.com/MAIF/otoroshi/tree/master/otoroshi/app/plugins)\n\n## Writing a plugin from Otoroshi UI\n\nLog into Otoroshi and go to `Settings (cog icon) / Plugins`. Here you can create multiple request transformer scripts and associate it with service descriptor later.\n\n@@@ div { .centered-img }\n\n@@@\n\nwhen you write for instance a transformer in the Otoroshi UI, do the following\n\n```scala\nimport akka.stream.Materializer\nimport env.Env\nimport models.{ApiKey, PrivateAppsUser, ServiceDescriptor}\nimport otoroshi.script._\nimport play.api.Logger\nimport play.api.mvc.{Result, Results}\nimport scala.util._\nimport scala.concurrent.{ExecutionContext, Future}\n\nclass MyTransformer extends RequestTransformer {\n\n val logger = Logger(\"my-transformer\")\n\n // implements the methods you want\n}\n\n// WARN: do not forget this line to provide a working instance of your transformer to Otoroshi\nnew MyTransformer()\n```\n\nYou can use the compile button to check if the script compiles, or code the transformer in your IDE (see next point).\n\nThen go to a service descriptor, scroll to the bottom of the page, and select your transformer in the list\n\n@@@ div { .centered-img }\n\n@@@\n\n## Providing a transformer from Java classpath\n\nYou can write your own transformer using your favorite IDE. Just create an SBT project with the following dependencies. It can be quite handy to manage the source code like any other piece of code, and it avoid the compilation time for the script at Otoroshi startup.\n\n```scala\nlazy val root = (project in file(\".\")).\n settings(\n inThisBuild(List(\n organization := \"com.example\",\n scalaVersion := \"2.12.7\",\n version := \"0.1.0-SNAPSHOT\"\n )),\n name := \"request-transformer-example\",\n libraryDependencies += \"fr.maif\" %% \"otoroshi\" % \"1.x.x\"\n )\n```\n\n@@@ warning\nyou MUST provide plugins that lies in the `otoroshi_plugins` package or in a sub-package of `otoroshi_plugins`. If you do not, your plugin will not be found by otoroshi. for example\n\n```scala\npackage otoroshi_plugins.com.my.company.myplugin\n```\n\nalso you don't have to instanciate your plugin at the end of the file like in the Otoroshi UI\n@@@\n\nWhen your code is ready, create a jar file \n\n```\nsbt package\n```\n\nand add the jar file to the Otoroshi classpath\n\n```sh\njava -cp \"/path/to/transformer.jar:$/path/to/otoroshi.jar\" play.core.server.ProdServerStart\n```\n\nthen, in your service descriptor, you can chose your transformer in the list. If you want to do it from the API, you have to defined the transformerRef using `cp:` prefix like \n\n```json\n{\n \"transformerRef\": \"cp:otoroshi_plugins.my.class.package.MyTransformer\"\n}\n```\n\n## Getting custom configuration from the Otoroshi config. file\n\nLet say you need to provide custom configuration values for a script, then you can customize a configuration file of Otoroshi\n\n```hocon\ninclude \"application.conf\"\n\notoroshi {\n scripts {\n enabled = true\n }\n}\n\nmy-transformer {\n env = \"prod\"\n maxRequestBodySize = 2048\n maxResponseBodySize = 2048\n}\n```\n\nthen start Otoroshi like\n\n```sh\njava -Dconfig.file=/path/to/custom.conf -jar otoroshi.jar\n```\n\nthen, in your transformer, you can write something like \n\n```scala\npackage otoroshi_plugins.com.example.otoroshi\n\nimport akka.stream.Materializer\nimport akka.stream.scaladsl._\nimport akka.util.ByteString\nimport env.Env\nimport models.{ApiKey, PrivateAppsUser, ServiceDescriptor}\nimport otoroshi.script._\nimport play.api.Logger\nimport play.api.mvc.{Result, Results}\nimport scala.util._\nimport scala.concurrent.{ExecutionContext, Future}\n\nclass BodyLengthLimiter extends RequestTransformer {\n\n override def def transformResponseWithCtx(ctx: TransformerResponseContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {\n val max = env.configuration.getOptional[Long](\"my-transformer.maxResponseBodySize\").getOrElse(Long.MaxValue)\n ctx.body.limitWeighted(max)(_.size)\n }\n\n override def transformRequestWithCtx(ctx: TransformerRequestContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {\n val max = env.configuration.getOptional[Long](\"my-transformer.maxRequestBodySize\").getOrElse(Long.MaxValue)\n ctx.body.limitWeighted(max)(_.size)\n }\n}\n```\n\n## Using a library that is not embedded in Otoroshi\n\nJust use the `classpath` option when running Otoroshi\n\n```sh\njava -cp \"/path/to/library.jar:$/path/to/otoroshi.jar\" play.core.server.ProdServerStart\n```\n\nBe carefull as your library can conflict with other libraries used by Otoroshi and affect its stability\n\n## Enabling plugins\n\nplugins can be enabled per service from the service settings page or globally from the danger zone in the plugins section.\n\n## Full example\n\na full external plugin example can be found @link:[here](https://github.com/mathieuancelin/otoroshi-wasmer-plugin)\n" - }, - { - "name": "index.md", - "id": "/plugins/index.md", - "url": "/plugins/index.html", - "title": "Otoroshi plugins", - "content": "# Otoroshi plugins\n\nIn this sections, you will find informations about Otoroshi plugins system\n\n* @ref:[Plugins system](./plugins.md)\n* @ref:[Create plugins](./create-plugins.md)\n* @ref:[Built in plugins](./built-in-plugins.md)\n\n@@@ index\n\n* [Plugins system](./plugins.md)\n* [Create plugins](./create-plugins.md)\n* [Built in plugins](./built-in-plugins.md)\n\n@@@" - }, - { - "name": "plugins.md", - "id": "/plugins/plugins.md", - "url": "/plugins/plugins.html", - "title": "Otoroshi plugins system", - "content": "# Otoroshi plugins system\n\nOtoroshi includes several extension points that allows you to create your own plugins and support stuff not supported by default\n\n## Available plugins\n\n@@@ div { .plugin .script }\n## Request Sink\n### Description\nUsed when no services are matched in Otoroshi. Can reply with any content.\n@@@\n\n@@@ div { .plugin .script }\n## Pre routing\n### Description\nUsed to extract values (like custom apikeys) and provide them to other plugins or Otoroshi engine\n@@@\n\n@@@ div { .plugin .script }\n## Access Validator\n### Description\nUsed to validate if a request can pass or not based on whatever you want\n@@@\n\n@@@ div { .plugin .script }\n## Request Transformer\n### Description\nUsed to transform request, responses and their body. Can be used to return arbitrary content\n@@@\n\n@@@ div { .plugin .script }\n## Event listener\n### Description\nAny plugin type can listen to Otoroshi internal events and react to thems\n@@@\n\n@@@ div { .plugin .script }\n## Job\n### Description\nTasks that can run automatically once, on be scheduled with a cron expression or every defined interval\n@@@\n\n@@@ div { .plugin .script }\n## Exporter\n### Description\nUsed to export events and Otoroshi alerts to an external source\n@@@\n\n@@@ div { .plugin .script }\n## Request handler\n### Description\nUsed to handle traffic without passing through Otoroshi routing and apply own rules\n@@@\n\n@@@ div { .plugin .script }\n## Nano app\n### Description\nUsed to write an api directly in Otoroshi in Scala language\n@@@" - }, - { - "name": "chaos-engineering.md", - "id": "/topics/chaos-engineering.md", - "url": "/topics/chaos-engineering.html", - "title": "Chaos engineering with the Snow Monkey", - "content": "# Chaos engineering with the Snow Monkey\n\nNihonzaru (the Snow Monkey) is the chaos engineering tool provided by Otoroshi. You can access it at `Settings (cog icon) / Snow Monkey`.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Chaos engineering\n\nOtoroshi offers some tools to introduce [chaos engineering](https://principlesofchaos.org/) in your everyday life. With chaos engineering, you will improve the resilience of your architecture by creating faults in production on running systems. With [Nihonzaru (the snow monkey)](https://en.wikipedia.org/wiki/Japanese_macaque) Otoroshi helps you to create faults on http request/response handled by Otoroshi. \n\n@@@ div { .centered-img }\n\n@@@\n\n## Settings\n\n@@@ div { .centered-img }\n\n@@@\n\nThe snow monkey let you define a few settings to work properly :\n\n* **Include user facing apps.**: you want to create fault in production, but maybe you don't want your users to enjoy some nice snow monkey generated error pages. Using this switch let you include of not user facing apps (ui apps). Each service descriptor has a `User facing app switch` that will be used by the snow monkey.\n* **Dry run**: when dry run is enabled, outages will be registered and will generate events and alerts (in the otoroshi eventing system) but requests won't be actualy impacted. It's a good way to prepare applications to the snow monkey habits\n* **Outage strategy**: Either `AllServicesPerGroup` or `OneServicePerGroup`. It means that only one service per group or all services per groups will have `n` outages (see next bullet point) during the snow monkey working period\n* **Outages per day**: during snow monkey working period, each service per group or one service per group will have only `n` outages registered \n* **Working period**: the snow monkey only works during a working period. Here you can defined when it starts and when it stops\n* **Outage duration**: here you can defined the bounds for the random outage duration when an outage is created on a service\n* **Impacted groups**: here you can define a list of service groups impacted by the snow monkey. If none is specified, then all service groups will be impacted\n\n## Faults\n\nWith the snow monkey, you can generate four types of faults\n\n* **Large request fault**: Add trailing bytes at the end of the request body (if one)\n* **Large response fault**: Add trailing bytes at the end of the response body\n* **Latency injection fault**: Add random response latency between two bounds\n* **Bad response injection fault**: Create predefined responses with custom headers, body and status code\n\nEach fault let you define a ratio for impacted requests. If you specify a ratio of `0.2`, then 20% of the requests for the impacte service will be impacted by this fault\n\n@@@ div { .centered-img }\n\n@@@\n\nThen you juste have to start the snow monkey and enjoy the show ;)\n\n@@@ div { .centered-img }\n\n@@@\n\n## Current outages\n\nIn the last section of the snow monkey page, you can see current outages (per service), when they started, their duration, etc ...\n\n@@@ div { .centered-img }\n\n@@@" - }, - { - "name": "dev-portal.md", - "id": "/topics/dev-portal.md", - "url": "/topics/dev-portal.html", - "title": "Developer portal with Daikoku", - "content": "# Developer portal with Daikoku\n\nWhile Otoroshi is the perfect tool to manage your webapps in a technical point of view it lacked of business perspective. This is not the case anymore with Daikoku.\n\nWhile Otoroshi is a standalone, Daikoku is a developer portal which stands in front of Otoroshi and provides some business feature.\n\nWhether you want to use Daikoku for your public APIs, you want to monetize or with your private APIs to provide some documentation, facilitation and self-service feature, it will be the perfect portal for Otoroshi.\n\n@@@div { .plugin .platform }\n## Daikoku\n\nRun your first Daikoku with a simple jar or with one Docker command.\n\n\n
\nTry Daikoku \n
\n@link:[With jar](https://maif.github.io/daikoku/devmanual/getdaikoku/frombinaries.html)\n@link:[With Docker](https://maif.github.io/daikoku/devmanual/getdaikoku/fromdocker.html)\n@@@\n\n@@@div { .plugin .platform }\n## Contribute\n\nDaikoku is opensource, so all contributions are welcome.\n\n\n@link:[Show the repository](https://github.com/MAIF/daikoku)\n@@@\n\n@@@div { .plugin .platform }\n## Documentation\n\nDaikoku and its UI are fully documented.\n\n\n@link:[Read the documentation](https://maif.github.io/daikoku/devmanual/)\n@@@\n\n" - }, - { - "name": "events-and-analytics.md", - "id": "/topics/events-and-analytics.md", - "url": "/topics/events-and-analytics.html", - "title": "Events and analytics", - "content": "# Events and analytics\n\nOtoroshi is a solution fully traced : calls to services, access to UI, creation of resources, etc.\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi\n@@@\n\n## Events\n\n* Analytics event\n* Gateway event\n* TCP event\n* Healthcheck event\n\n## Event log\n\nOtoroshi can read his own exported events from an Elasticsearch instance, set up in the danger zone. Theses events are available from the UI, at the following route: `https://xxxxx/bo/dashboard/events`.\n\nThe `Global events` page display all events of **GatewayEvent** type. This page is a way to quickly read an interval of events and can be used in addition of a Kibana instance.\n\nFor each event, a list of information will be displayed and an additional button `content` to watch the full content of the event, at the JSON format. \n\n## Alerts \n\n* `MaxConcurrentRequestReachedAlert`: happening when the handled requests number are greater than the limit of concurrent requests indicated in the global configuration of Otoroshi\n* `CircuitBreakerOpenedAlert`: happening when the circuit breaker pass from closed to opened\n* `CircuitBreakerClosedAlert`: happening when the circuit breaker pass from opened to closed\n* `SessionDiscardedAlert`: send when an admin discarded an admin sessions\n* `SessionsDiscardedAlert`: send when an admin discarded all admin sessions\n* `PanicModeAlert`: send when panic mode is enabled\n* `OtoroshiExportAlert`: send when otoroshi global configuration is exported\n* `U2FAdminDeletedAlert`: send when an admin has deleted an other admin user\n* `BlackListedBackOfficeUserAlert`: send when a blacklisted user has tried to acccess to the UI\n* `AdminLoggedInAlert`: send when an user admin has logged to the UI\n* `AdminFirstLogin`: send when an user admin has successfully logged to the UI for the first time\n* `AdminLoggedOutAlert`: send when an user admin has logged out from Otoroshi\n* `GlobalConfigModification`: send when an user amdin has changed the global configuration of Otoroshi\n* `RevokedApiKeyUsageAlert`: send when an user admin has revoked an apikey\n* `ServiceGroupCreatedAlert`: send when an user admin has created a service group\n* `ServiceGroupUpdatedAlert`: send when an user admin has updated a service group\n* `ServiceGroupDeletedAlert`: send when an user admin has deleted a service group\n* `ServiceCreatedAlert`: send when an user admin has created a tcp service\n* `ServiceUpdatedAlert`: send when an user admin has updated a tcp service\n* `ServiceDeletedAlert`: send when an user admin has deleted a tcp service\n* `ApiKeyCreatedAlert`: send when an user admin has crated a new apikey\n* `ApiKeyUpdatedAlert`: send when an user admin has updated a new apikey\n* `ApiKeyDeletedAlert`: send when an user admin has deleted a new apikey\n\n## Audit\n\nWith Otoroshi, any admin action and any sucpicious/alert action is recorded. These records are stored in Otoroshi’s datastore (only the last n records, defined by the `otoroshi.events.maxSize` config key). All the records can be send through the analytics mechanism (WebHook, Kafka, Elastic) for external and/or further usage. We recommand sending away those records for security reasons.\n\nOtoroshi keep the following list of information for each executed action:\n\n* `Date`: moment of the action\n* `User`: name of the owner\n* `From`: IP of the concerned user\n* `Action`: action performed by the person. The possible actions are:\n\n * `ACCESS_APIKEY`: User accessed a apikey\n * `ACCESS_ALL_APIKEYS`: User accessed all apikeys\n * `CREATE_APIKEY`: User created a apikey\n * `UPDATE_APIKEY`: User updated a apikey\n * `DELETE_APIKEY`: User deleted a apikey\n * `ACCESS_AUTH_MODULE`: User accessed an Auth. module\n * `ACCESS_ALL_AUTH_MODULES`: User accessed all Auth. modules\n * `CREATE_AUTH_MODULE`: User created an Auth. module\n * `UPDATE_AUTH_MODULE`: User updated an Auth. module\n * `DELETE_AUTH_MODULE`: User deleted an Auth. module\n * `ACCESS_CERTIFICATE`: User accessed a certificate\n * `ACCESS_ALL_CERTIFICATES`: User accessed all certificates\n * `CREATE_CERTIFICATE`: User created a certificate\n * `UPDATE_CERTIFICATE`: User updated a certificate\n * `DELETE_CERTIFICATE`: User deleted a certificate\n * `ACCESS_CLIENT_CERT_VALIDATOR`: User accessed a client cert. validator\n * `ACCESS_ALL_CLIENT_CERT_VALIDATORS`: User accessed all client cert. validators\n * `CREATE_CLIENT_CERT_VALIDATOR`: User created a client cert. validator\n * `UPDATE_CLIENT_CERT_VALIDATOR`: User updated a client cert. validator\n * `DELETE_CLIENT_CERT_VALIDATOR`: User deleted a client cert. validator\n * `ACCESS_DATA_EXPORTER_CONFIG`: User accessed a data exporter config\n * `ACCESS_ALL_DATA_EXPORTER_CONFIG`: User accessed all data exporter config\n * `CREATE_DATA_EXPORTER_CONFIG`: User created a data exporter config\n * `UPDATE_DATA_EXPORTER_CONFIG`: User updated a data exporter config\n * `DELETE_DATA_EXPORTER_CONFIG`: User deleted a data exporter config\n * `ACCESS_GLOBAL_JWT_VERIFIER`: User accessed a global jwt verifier\n * `ACCESS_ALL_GLOBAL_JWT_VERIFIERS`: User accessed all global jwt verifiers\n * `CREATE_GLOBAL_JWT_VERIFIER`: User created a global jwt verifier\n * `UPDATE_GLOBAL_JWT_VERIFIER`: User updated a global jwt verifier\n * `DELETE_GLOBAL_JWT_VERIFIER`: User deleted a global jwt verifier\n * `ACCESS_SCRIPT`: User accessed a script\n * `ACCESS_ALL_SCRIPTS`: User accessed all scripts\n * `CREATE_SCRIPT`: User created a script\n * `UPDATE_SCRIPT`: User updated a script\n * `DELETE_SCRIPT`: User deleted a Script\n * `ACCESS_SERVICES_GROUP`: User accessed a service group\n * `ACCESS_ALL_SERVICES_GROUPS`: User accessed all services groups\n * `CREATE_SERVICE_GROUP`: User created a service group\n * `UPDATE_SERVICE_GROUP`: User updated a service group\n * `DELETE_SERVICE_GROUP`: User deleted a service group\n * `ACCESS_SERVICES_FROM_SERVICES_GROUP`: User accessed all services from a services group\n * `ACCESS_TCP_SERVICE`: User accessed a tcp service\n * `ACCESS_ALL_TCP_SERVICES`: User accessed all tcp services\n * `CREATE_TCP_SERVICE`: User created a tcp service\n * `UPDATE_TCP_SERVICE`: User updated a tcp service\n * `DELETE_TCP_SERVICE`: User deleted a tcp service\n * `ACCESS_TEAM`: User accessed a Team\n * `ACCESS_ALL_TEAMS`: User accessed all teams\n * `CREATE_TEAM`: User created a team\n * `UPDATE_TEAM`: User updated a team\n * `DELETE_TEAM`: User deleted a team\n * `ACCESS_TENANT`: User accessed a Tenant\n * `ACCESS_ALL_TENANTS`: User accessed all tenants\n * `CREATE_TENANT`: User created a tenant\n * `UPDATE_TENANT`: User updated a tenant\n * `DELETE_TENANT`: User deleted a tenant\n * `SERVICESEARCH`: User searched for a service\n * `ACTIVATE_PANIC_MODE`: Admin activated panic mode\n\n\n* `Message`: explicit message about the action (example: the `SERVICESEARCH` action happened when an `user searched for a service`)\n* `Content`: all information at JSON format\n\n## Global metrics\n\nThe global metrics are displayed on the index page of the Otoroshi UI. Otoroshi provides information about :\n\n* the number of requests served\n* the amount of data received and sended\n* the number of concurrent requests\n* the number of requests per second\n* the current overhead\n\nMore metrics can be found on the **Global analytics** page (available at https://xxxxxx/bo/dashboard/stats).\n\n## Monitoring services\n\nOnce you have declared services, you can monitor them with Otoroshi. \n\nLet's starting by setup Otoroshi to push events to an elastic cluster via a data exporter. Then you will can setup Otoroshi events read from an elastic cluster. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (read)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service healthcheck\n\nIf you have defined an health check URL in the service descriptor, you can access the health check page from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service live stats\n\nYou can also monitor live stats like total of served request, average response time, average overhead, etc. The live stats page can be accessed from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service analytics\n\nYou can also get some aggregated metrics. The analytics page can be accessed from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n## New proxy engine\n\n### Debug reporting\n\nwhen using the @ref:[new proxy engine](../next/engine.md), when a route or the global config. enables traffic capture using the `debug_flow` flag, events of type `RequestFlowReport` are generated\n\n### Traffic capture\n\nwhen using the @ref:[new proxy engine](../next/engine.md), when a route or the global config. enables traffic capture using the `capture` flag, events of type `TrafficCaptureEvent` are generated. It contains everything that compose otoroshi input http request and output http responses\n" - }, - { - "name": "expression-language.md", - "id": "/topics/expression-language.md", - "url": "/topics/expression-language.html", - "title": "Expression language", - "content": "# Expression language\n\n- [Documentation and examples](#documentation-and-examples)\n- [Test the expression language](#test-the-expression-language)\n\nThe expression language provides an important mechanism for accessing and manipulating Otoroshi data on different inputs. For example, with this mechanism, you can mapping a claim of an inconming token directly in a claim of a generated token (using @ref:[JWT verifiers](../entities/jwt-verifiers.md)). You can add information of the service descriptor traversed such as the domain of the service or the name of the service. This information can be useful on the backend service.\n\n## Documentation and examples\n\n@@@div { #expressions }\n \n@@@\n\nIf an input contains a string starting by `${`, Otoroshi will try to evaluate the content. If the content doesn't match a known expression,\nthe 'bad-expr' value will be set.\n\n## Test the expression language\n\nYou can test to get the same values than the right part by creating these following services. \n\n```sh\n# Let's start by downloading the latest Otoroshi.\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n\n# Once downloading, run Otoroshi.\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n\n# Create a proxy of the mirror.otoroshi.io on http://myservice.oto.tools:8080\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/services \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"enforceSecureCommunication\":false,\"forceHttps\":false,\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"id\":\"expression-language-api-service\",\"name\":\"expression-language\",\"description\":\"expression-language\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"api\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[],\"privatePatterns\":[\"/.*\"],\"kind\":\"ServiceDescriptor\",\"additionalHeaders\":{\"my-expr-header.date\":\"${date}\",\"my-expr-header.date-with-format\":\"${date.format('yyy-MM-dd')}\",\"my-expr-header.request.full-url\":\"${req.fullUrl}\",\"my-expr-header.request.path\":\"${req.path}\",\"my-expr-header.request.uri\":\"${req.uri}\",\"my-expr-header.request.host\":\"${req.host}\",\"my-expr-header.request.domain\":\"${req.domain}\",\"my-expr-header.request.method\":\"${req.method}\",\"my-expr-header.request.protocol\":\"${req.protocol}\",\"my-expr-header.request.unknown-header\":\"${req.headers.foob:default value}\",\"my-expr-header.request.header\":\"${req.headers.foo}\",\"my-expr-header.request.unknown-query\":\"${req.query.foob:default value}\",\"my-expr-header.request.query\":\"${req.query.foo}\",\"my-expr-header.service-domain\":\"${service.domain}\",\"my-expr-header.service-subdomain\":\"${service.subdomain}\",\"my-expr-header.service-tld\":\"${service.tld}\",\"my-expr-header.service-env\":\"${service.env}\",\"my-expr-header.service-id\":\"${service.id}\",\"my-expr-header.service-name\":\"${service.name}\",\"my-expr-header.service-unknown-group\":\"${service.groups['0':'unkown group']}\",\"my-expr-header.service-group\":\"${service.groups['0']}\",\"my-expr-header.service-unknown-metadata\":\"${service.metadata.test:default-value}\",\"my-expr-header.service-metadata\":\"${service.metadata.foo}\",\"my-expr-header.apikey.name\":\"${apikey.name}\",\"my-expr-header.apikey.id\":\"${apikey.id}\",\"my-expr-header.apikey.unknown-metadata\":\"${apikey.metadata.myfield:default value}\",\"my-expr-header.apikey.metadata\":\"${apikey.metadata.foo}\",\"my-expr-header.apikey.unknown-tag\":\"${apikey.tags['0':'no-found-tag']}\",\"my-expr-header.apikey.tag\":\"${apikey.tags['0']}\",\"my-expr-header.token.replace-header-value\":\"${token.foo.replace('o','a')}\",\"my-expr-header.token.replace-header-all-value\":\"${token.foo.replaceAll('o','a')}\",\"my-expr-header.token.unknown-fields\":\"${token.foob|token.foob2:not-found}\",\"my-expr-header.token.foo-field\":\"${token.foob|token.foo}\",\"my-expr-header.token.unknown-foo-field\":\"${token.foob:not-found-foob}\",\"my-expr-header.token.unknown-foo\":\"${token.foo}\",\"my-expr-header.env.unknown-field\":\"${env.java_h:not-found-java_h}\",\"my-expr-header.env.path\":\"${env.PATH}\",\"my-expr-header.config.unknown-port-field\":\"${config.http.ports:not-found}\",\"my-expr-header.config.port\":\"${config.http.port}\",\"my-expr-header.ctx.replace-field-value\":\"${ctx.foo.replace('o','a')}\",\"my-expr-header.ctx.replace-field-all-value\":\"${ctx.foo.replaceAll('o','a')}\",\"my-expr-header.ctx.unknown-fields\":\"${ctx.foob|ctx.foot:not-found}\",\"my-expr-header.ctx.foo-field\":\"${ctx.foob|ctx.foo}\",\"my-expr-header.ctx.default-value\":\"${ctx.foob:other}\",\"my-expr-header.ctx.foo\":\"${ctx.foo}\",\"my-expr-header.ctx.useragent\":\"${ctx.useragent.foo}\",\"my-expr-header.ctx.geolocation\":\"${ctx.geolocation.foo}\"}}\nEOF\n\n# Create an authentication module to protect the next service.\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/auths \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"type\":\"basic\",\"id\":\"auth_mod_in_memory_auth\",\"name\":\"in-memory-auth\",\"desc\":\"in-memory-auth\",\"users\":[{\"name\":\"User Otoroshi\",\"password\":\"$2a$10$oIf4JkaOsfiypk5ZK8DKOumiNbb2xHMZUkYkuJyuIqMDYnR/zXj9i\",\"email\":\"user@foo.bar\",\"metadata\":{\"username\":\"roger\"},\"tags\":[\"foo\"],\"webauthn\":null,\"rights\":[{\"tenant\":\"*:r\",\"teams\":[\"*:r\"]}]}],\"sessionCookieValues\":{\"httpOnly\":true,\"secure\":false}}\nEOF\n\n# Create the same proxy but protected by an authentication memory module (in order to retrieve the user's information after they have successfully logged in)\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/services \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"enforceSecureCommunication\":false,\"forceHttps\":false,\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"id\":\"expression-language-webapp\",\"name\":\"webapp\",\"description\":\"webapp\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"webapp\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"authConfigRef\":\"auth_mod_in_memory_auth\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"/.*\"],\"privateApp\":true,\"privatePatterns\":[],\"kind\":\"ServiceDescriptor\",\"additionalHeaders\":{\"my-expr-header.user\":\"${user.name}\",\"my-expr-header.user.email\":\"${user.email}\",\"my-expr-header.user.unknown-metadata\":\"${user.metadata.foo:'not-found'}\",\"my-expr-header.user.metadata\":\"${user.metadata.username}\",\"my-expr-header.user.unknown-profile-field\":\"${user.profile.username:'not-found'}\",\"my-expr-header.user.profile-field\":\"${user.profile.name}\"}}\nEOF\n```\n\nThen try to call the first service.\n\n```sh\ncurl http://api.oto.tools:8080/api/\\?foo\\=bar \\\n-H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJmb28iOiJiYXIifQ.lV130dFXR3bNtWBkwwf9dLmfsRVmnZhfYF9gvAaRzF8\" \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H \"foo: bar\" | jq\n```\n\nThis will returns the list of the received headers by the mirror.\n\n```json\n{\n ...\n \"headers\": {\n ...\n \"my-expr-header.date\": \"2021-11-26T10:54:51.112+01:00\",\n \"my-expr-header.ctx.foo\": \"no-ctx-foo\",\n \"my-expr-header.env.path\": \"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\",\n \"my-expr-header.apikey.id\": \"admin-api-apikey-id\",\n \"my-expr-header.apikey.tag\": \"one-tag\",\n \"my-expr-header.service-id\": \"expression-language-api-service\",\n \"my-expr-header.apikey.name\": \"Otoroshi Backoffice ApiKey\",\n \"my-expr-header.config.port\": \"8080\",\n \"my-expr-header.request.uri\": \"/api/?foo=bar\",\n \"my-expr-header.service-env\": \"prod\",\n \"my-expr-header.service-tld\": \"oto.tools\",\n \"my-expr-header.request.host\": \"api.oto.tools:8080\",\n \"my-expr-header.request.path\": \"/api/\",\n \"my-expr-header.service-name\": \"expression-language\",\n \"my-expr-header.ctx.foo-field\": \"no-ctx-foob-foo\",\n \"my-expr-header.ctx.useragent\": \"no-ctx-useragent.foo\",\n \"my-expr-header.request.query\": \"bar\",\n \"my-expr-header.service-group\": \"default\",\n \"my-expr-header.request.domain\": \"api.oto.tools\",\n \"my-expr-header.request.header\": \"bar\",\n \"my-expr-header.request.method\": \"GET\",\n \"my-expr-header.service-domain\": \"api.oto.tools\",\n \"my-expr-header.apikey.metadata\": \"bar\",\n \"my-expr-header.ctx.geolocation\": \"no-ctx-geolocation.foo\",\n \"my-expr-header.token.foo-field\": \"no-token-foob-foo\",\n \"my-expr-header.date-with-format\": \"2021-11-26\",\n \"my-expr-header.request.full-url\": \"http://api.oto.tools:8080/api/?foo=bar\",\n \"my-expr-header.request.protocol\": \"http\",\n \"my-expr-header.service-metadata\": \"no-meta-foo\",\n \"my-expr-header.ctx.default-value\": \"other\",\n \"my-expr-header.env.unknown-field\": \"not-found-java_h\",\n \"my-expr-header.service-subdomain\": \"api\",\n \"my-expr-header.token.unknown-foo\": \"no-token-foo\",\n \"my-expr-header.apikey.unknown-tag\": \"one-tag\",\n \"my-expr-header.ctx.unknown-fields\": \"not-found\",\n \"my-expr-header.token.unknown-fields\": \"not-found\",\n \"my-expr-header.request.unknown-query\": \"default value\",\n \"my-expr-header.service-unknown-group\": \"default\",\n \"my-expr-header.request.unknown-header\": \"default value\",\n \"my-expr-header.apikey.unknown-metadata\": \"default value\",\n \"my-expr-header.ctx.replace-field-value\": \"no-ctx-foo\",\n \"my-expr-header.token.unknown-foo-field\": \"not-found-foob\",\n \"my-expr-header.service-unknown-metadata\": \"default-value\",\n \"my-expr-header.config.unknown-port-field\": \"not-found\",\n \"my-expr-header.token.replace-header-value\": \"no-token-foo\",\n \"my-expr-header.ctx.replace-field-all-value\": \"no-ctx-foo\",\n \"my-expr-header.token.replace-header-all-value\": \"no-token-foo\",\n }\n}\n```\n\nThen try the second call to the webapp. Navigate on your browser to `http://webapp.oto.tools:8080`. Continue with `user@foo.bar` as user and `password` as credential.\n\nThis should output:\n\n```json\n{\n ...\n \"headers\": {\n ...\n \"my-expr-header.user\": \"User Otoroshi\",\n \"my-expr-header.user.email\": \"user@foo.bar\",\n \"my-expr-header.user.metadata\": \"roger\",\n \"my-expr-header.user.profile-field\": \"User Otoroshi\",\n \"my-expr-header.user.unknown-metadata\": \"not-found\",\n \"my-expr-header.user.unknown-profile-field\": \"not-found\",\n }\n}\n```" - }, - { - "name": "index.md", - "id": "/topics/index.md", - "url": "/topics/index.html", - "title": "Detailed topics", - "content": "# Detailed topics\n\nIn this sections, you will find informations about various Otoroshi topics \n\n* @ref:[Chaos engineering](./chaos-engineering.md)\n* @ref:[TLS](./tls.md)\n* @ref:[Otoroshi's PKI](./pki.md)\n* @ref:[Monitoring](./monitoring.md)\n* @ref:[Events and analytics](./events-and-analytics.md)\n* @ref:[Developer portal with Daikoku](./dev-portal.md)\n* @ref:[Sessions management](./sessions-mgmt.md)\n* @ref:[The Otoroshi communication protocol](./otoroshi-protocol.md)\n* @ref:[Expression language](./expression-language.md)\n* @ref:[Otoroshi user rights](./user-rights.md)\n\n@@@ index\n\n* [Chaos engineering](./chaos-engineering.md)\n* [TLS](./tls.md)\n* [Otoroshi's PKI](./pki.md)\n* [Monitoring](./monitoring.md)\n* [Events and analytics](./events-and-analytics.md)\n* [Developer portal with Daikoku](./dev-portal.md)\n* [Sessions management](./sessions-mgmt.md)\n* [The Otoroshi communication protocol](./otoroshi-protocol.md)\n* [Expression language](./expression-language.md)\n* [Otoroshi user rights](./user-rights.md)\n \n@@@\n" - }, - { - "name": "monitoring.md", - "id": "/topics/monitoring.md", - "url": "/topics/monitoring.html", - "title": "Monitoring", - "content": "# Monitoring\n\nThe Otoroshi API exposes two endpoints to know more about instance health. All the following endpoint are exposed on the instance host through it's ip address. It is also exposed on the otoroshi api hostname and the otoroshi backoffice hostname\n\n* `/health`: the health of the Otoroshi instance\n* `/metrics`: the metrics of the Otoroshi instance, either in JSON or Prometheus format using the `Accept` header (with `application/json` / `application/prometheus` values) or the `format` query param (with `json` or `prometheus` values)\n* `/live`: returns an http 200 response `{\"live\": true}` when the service is alive\n* `/ready`: return an http 200 response `{\"ready\": true}` when the instance is ready to accept traffic (certs synced, plugins compiled, etc). if not, returns http 503 `{\"ready\": false}`\n* `/startup`: return an http 200 response `{\"started\": true}` when the instance is ready to accept traffic (certs synced, plugins compiled, etc). if not, returns http 503 `{\"started\": false}`\n\nthose routes are also available on any hostname leading to otoroshi with a twist in the URL\n\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/health\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/metrics\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/live\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/ready\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/startup\n\n## Endpoints security\n\nThe two endpoints are exposed publicly on the Otoroshi admin api. But you can remove the corresponding public pattern and query the endpoints using standard apikeys. If you don't want to use apikeys but don't want to expose the endpoints publicly, you can defined two config. variables (`otoroshi.health.accessKey` or `HEALTH_ACCESS_KEY` and `otoroshi.metrics.accessKey` or `OTOROSHI_METRICS_ACCESS_KEY`) that will hold an access key for the endpoints. Then you can call the endpoints with an `access_key` query param with the value defined in the config. If you don't defined `otoroshi.metrics.accessKey` but define `otoroshi.health.accessKey`, `otoroshi.metrics.accessKey` will have the value of `otoroshi.health.accessKey`.\n \n## Examples\n\nlet say `otoroshi.health.accessKey` has value `MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY`\n\n```sh\n$ curl http://otoroshi-api.oto.tools:8080/health\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n{\"otoroshi\":\"healthy\",\"datastore\":\"healthy\"}\n\n$ curl -H 'Accept: application/json' http://otoroshi-api.oto.tools:8080/metrics\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n{\"version\":\"4.0.0\",\"gauges\":{\"attr.app.commit\":{\"value\":\"xxxx\"},\"attr.app.id\":{\"value\":\"xxxx\"},\"attr.cluster.mode\":{\"value\":\"Leader\"},\"attr.cluster.name\":{\"value\":\"otoroshi-leader-0\"},\"attr.instance.env\":{\"value\":\"prod\"},\"attr.instance.id\":{\"value\":\"xxxx\"},\"attr.instance.number\":{\"value\":\"0\"},\"attr.jvm.cpu.usage\":{\"value\":136},\"attr.jvm.heap.size\":{\"value\":1409},\"attr.jvm.heap.used\":{\"value\":112},\"internals.0.concurrent-requests\":{\"value\":1},\"internals.global.throttling-quotas\":{\"value\":2},\"jvm.attr.name\":{\"value\":\"2085@xxxx\"},\"jvm.attr.uptime\":{\"value\":2296900},\"jvm.attr.vendor\":{\"value\":\"JDK11\"},\"jvm.gc.PS-MarkSweep.count\":{\"value\":3},\"jvm.gc.PS-MarkSweep.time\":{\"value\":261},\"jvm.gc.PS-Scavenge.count\":{\"value\":12},\"jvm.gc.PS-Scavenge.time\":{\"value\":161},\"jvm.memory.heap.committed\":{\"value\":1477967872},\"jvm.memory.heap.init\":{\"value\":1690304512},\"jvm.memory.heap.max\":{\"value\":3005218816},\"jvm.memory.heap.usage\":{\"value\":0.03916456777568639},\"jvm.memory.heap.used\":{\"value\":117698096},\"jvm.memory.non-heap.committed\":{\"value\":166445056},\"jvm.memory.non-heap.init\":{\"value\":7667712},\"jvm.memory.non-heap.max\":{\"value\":994050048},\"jvm.memory.non-heap.usage\":{\"value\":0.1523920694986979},\"jvm.memory.non-heap.used\":{\"value\":151485344},\"jvm.memory.pools.CodeHeap-'non-nmethods'.committed\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-nmethods'.max\":{\"value\":5832704},\"jvm.memory.pools.CodeHeap-'non-nmethods'.usage\":{\"value\":0.28408093398876405},\"jvm.memory.pools.CodeHeap-'non-nmethods'.used\":{\"value\":1656960},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.committed\":{\"value\":11796480},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.max\":{\"value\":122912768},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.usage\":{\"value\":0.09536102872567315},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.used\":{\"value\":11721088},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.committed\":{\"value\":37355520},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.max\":{\"value\":122912768},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.usage\":{\"value\":0.2538573047187417},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.used\":{\"value\":31202304},\"jvm.memory.pools.Compressed-Class-Space.committed\":{\"value\":14942208},\"jvm.memory.pools.Compressed-Class-Space.init\":{\"value\":0},\"jvm.memory.pools.Compressed-Class-Space.max\":{\"value\":367001600},\"jvm.memory.pools.Compressed-Class-Space.usage\":{\"value\":0.033858838762555805},\"jvm.memory.pools.Compressed-Class-Space.used\":{\"value\":12426248},\"jvm.memory.pools.Metaspace.committed\":{\"value\":99794944},\"jvm.memory.pools.Metaspace.init\":{\"value\":0},\"jvm.memory.pools.Metaspace.max\":{\"value\":375390208},\"jvm.memory.pools.Metaspace.usage\":{\"value\":0.25168142904782426},\"jvm.memory.pools.Metaspace.used\":{\"value\":94478744},\"jvm.memory.pools.PS-Eden-Space.committed\":{\"value\":349700096},\"jvm.memory.pools.PS-Eden-Space.init\":{\"value\":422576128},\"jvm.memory.pools.PS-Eden-Space.max\":{\"value\":1110966272},\"jvm.memory.pools.PS-Eden-Space.usage\":{\"value\":0.07505125052077188},\"jvm.memory.pools.PS-Eden-Space.used\":{\"value\":83379408},\"jvm.memory.pools.PS-Eden-Space.used-after-gc\":{\"value\":0},\"jvm.memory.pools.PS-Old-Gen.committed\":{\"value\":1127219200},\"jvm.memory.pools.PS-Old-Gen.init\":{\"value\":1127219200},\"jvm.memory.pools.PS-Old-Gen.max\":{\"value\":2253914112},\"jvm.memory.pools.PS-Old-Gen.usage\":{\"value\":0.014950035505168354},\"jvm.memory.pools.PS-Old-Gen.used\":{\"value\":33696096},\"jvm.memory.pools.PS-Old-Gen.used-after-gc\":{\"value\":23791152},\"jvm.memory.pools.PS-Survivor-Space.committed\":{\"value\":1048576},\"jvm.memory.pools.PS-Survivor-Space.init\":{\"value\":70254592},\"jvm.memory.pools.PS-Survivor-Space.max\":{\"value\":1048576},\"jvm.memory.pools.PS-Survivor-Space.usage\":{\"value\":0.59375},\"jvm.memory.pools.PS-Survivor-Space.used\":{\"value\":622592},\"jvm.memory.pools.PS-Survivor-Space.used-after-gc\":{\"value\":622592},\"jvm.memory.total.committed\":{\"value\":1644412928},\"jvm.memory.total.init\":{\"value\":1697972224},\"jvm.memory.total.max\":{\"value\":3999268864},\"jvm.memory.total.used\":{\"value\":269184904},\"jvm.thread.blocked.count\":{\"value\":0},\"jvm.thread.count\":{\"value\":82},\"jvm.thread.daemon.count\":{\"value\":11},\"jvm.thread.deadlock.count\":{\"value\":0},\"jvm.thread.deadlocks\":{\"value\":[]},\"jvm.thread.new.count\":{\"value\":0},\"jvm.thread.runnable.count\":{\"value\":25},\"jvm.thread.terminated.count\":{\"value\":0},\"jvm.thread.timed_waiting.count\":{\"value\":10},\"jvm.thread.waiting.count\":{\"value\":47}},\"counters\":{},\"histograms\":{},\"meters\":{},\"timers\":{}}\n\n$ curl -H 'Accept: application/prometheus' http://otoroshi-api.oto.tools:8080/metrics\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n# TYPE attr_jvm_cpu_usage gauge\nattr_jvm_cpu_usage 83.0\n# TYPE attr_jvm_heap_size gauge\nattr_jvm_heap_size 1409.0\n# TYPE attr_jvm_heap_used gauge\nattr_jvm_heap_used 220.0\n# TYPE internals_0_concurrent_requests gauge\ninternals_0_concurrent_requests 1.0\n# TYPE internals_global_throttling_quotas gauge\ninternals_global_throttling_quotas 3.0\n# TYPE jvm_attr_uptime gauge\njvm_attr_uptime 2372614.0\n# TYPE jvm_gc_PS_MarkSweep_count gauge\njvm_gc_PS_MarkSweep_count 3.0\n# TYPE jvm_gc_PS_MarkSweep_time gauge\njvm_gc_PS_MarkSweep_time 261.0\n# TYPE jvm_gc_PS_Scavenge_count gauge\njvm_gc_PS_Scavenge_count 12.0\n# TYPE jvm_gc_PS_Scavenge_time gauge\njvm_gc_PS_Scavenge_time 161.0\n# TYPE jvm_memory_heap_committed gauge\njvm_memory_heap_committed 1.477967872E9\n# TYPE jvm_memory_heap_init gauge\njvm_memory_heap_init 1.690304512E9\n# TYPE jvm_memory_heap_max gauge\njvm_memory_heap_max 3.005218816E9\n# TYPE jvm_memory_heap_usage gauge\njvm_memory_heap_usage 0.07680553268571043\n# TYPE jvm_memory_heap_used gauge\njvm_memory_heap_used 2.30817432E8\n# TYPE jvm_memory_non_heap_committed gauge\njvm_memory_non_heap_committed 1.66510592E8\n# TYPE jvm_memory_non_heap_init gauge\njvm_memory_non_heap_init 7667712.0\n# TYPE jvm_memory_non_heap_max gauge\njvm_memory_non_heap_max 9.94050048E8\n# TYPE jvm_memory_non_heap_usage gauge\njvm_memory_non_heap_usage 0.15262878997416435\n# TYPE jvm_memory_non_heap_used gauge\njvm_memory_non_heap_used 1.51720656E8\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__committed gauge\njvm_memory_pools_CodeHeap__non_nmethods__committed 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__init gauge\njvm_memory_pools_CodeHeap__non_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__max gauge\njvm_memory_pools_CodeHeap__non_nmethods__max 5832704.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__usage gauge\njvm_memory_pools_CodeHeap__non_nmethods__usage 0.28408093398876405\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__used gauge\njvm_memory_pools_CodeHeap__non_nmethods__used 1656960.0\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__committed gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__committed 1.1862016E7\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__init gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__max gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__max 1.22912768E8\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__usage gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__usage 0.09610562183417755\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__used gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__used 1.1812608E7\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__committed gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__committed 3.735552E7\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__init gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__max gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__max 1.22912768E8\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__usage gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__usage 0.25493618368435084\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__used gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__used 3.1334912E7\n# TYPE jvm_memory_pools_Compressed_Class_Space_committed gauge\njvm_memory_pools_Compressed_Class_Space_committed 1.4942208E7\n# TYPE jvm_memory_pools_Compressed_Class_Space_init gauge\njvm_memory_pools_Compressed_Class_Space_init 0.0\n# TYPE jvm_memory_pools_Compressed_Class_Space_max gauge\njvm_memory_pools_Compressed_Class_Space_max 3.670016E8\n# TYPE jvm_memory_pools_Compressed_Class_Space_usage gauge\njvm_memory_pools_Compressed_Class_Space_usage 0.03386023385184152\n# TYPE jvm_memory_pools_Compressed_Class_Space_used gauge\njvm_memory_pools_Compressed_Class_Space_used 1.242676E7\n# TYPE jvm_memory_pools_Metaspace_committed gauge\njvm_memory_pools_Metaspace_committed 9.9794944E7\n# TYPE jvm_memory_pools_Metaspace_init gauge\njvm_memory_pools_Metaspace_init 0.0\n# TYPE jvm_memory_pools_Metaspace_max gauge\njvm_memory_pools_Metaspace_max 3.75390208E8\n# TYPE jvm_memory_pools_Metaspace_usage gauge\njvm_memory_pools_Metaspace_usage 0.25170985813247426\n# TYPE jvm_memory_pools_Metaspace_used gauge\njvm_memory_pools_Metaspace_used 9.4489416E7\n# TYPE jvm_memory_pools_PS_Eden_Space_committed gauge\njvm_memory_pools_PS_Eden_Space_committed 3.49700096E8\n# TYPE jvm_memory_pools_PS_Eden_Space_init gauge\njvm_memory_pools_PS_Eden_Space_init 4.22576128E8\n# TYPE jvm_memory_pools_PS_Eden_Space_max gauge\njvm_memory_pools_PS_Eden_Space_max 1.110966272E9\n# TYPE jvm_memory_pools_PS_Eden_Space_usage gauge\njvm_memory_pools_PS_Eden_Space_usage 0.17698545577448457\n# TYPE jvm_memory_pools_PS_Eden_Space_used gauge\njvm_memory_pools_PS_Eden_Space_used 1.96624872E8\n# TYPE jvm_memory_pools_PS_Eden_Space_used_after_gc gauge\njvm_memory_pools_PS_Eden_Space_used_after_gc 0.0\n# TYPE jvm_memory_pools_PS_Old_Gen_committed gauge\njvm_memory_pools_PS_Old_Gen_committed 1.1272192E9\n# TYPE jvm_memory_pools_PS_Old_Gen_init gauge\njvm_memory_pools_PS_Old_Gen_init 1.1272192E9\n# TYPE jvm_memory_pools_PS_Old_Gen_max gauge\njvm_memory_pools_PS_Old_Gen_max 2.253914112E9\n# TYPE jvm_memory_pools_PS_Old_Gen_usage gauge\njvm_memory_pools_PS_Old_Gen_usage 0.014950035505168354\n# TYPE jvm_memory_pools_PS_Old_Gen_used gauge\njvm_memory_pools_PS_Old_Gen_used 3.3696096E7\n# TYPE jvm_memory_pools_PS_Old_Gen_used_after_gc gauge\njvm_memory_pools_PS_Old_Gen_used_after_gc 2.3791152E7\n# TYPE jvm_memory_pools_PS_Survivor_Space_committed gauge\njvm_memory_pools_PS_Survivor_Space_committed 1048576.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_init gauge\njvm_memory_pools_PS_Survivor_Space_init 7.0254592E7\n# TYPE jvm_memory_pools_PS_Survivor_Space_max gauge\njvm_memory_pools_PS_Survivor_Space_max 1048576.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_usage gauge\njvm_memory_pools_PS_Survivor_Space_usage 0.59375\n# TYPE jvm_memory_pools_PS_Survivor_Space_used gauge\njvm_memory_pools_PS_Survivor_Space_used 622592.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_used_after_gc gauge\njvm_memory_pools_PS_Survivor_Space_used_after_gc 622592.0\n# TYPE jvm_memory_total_committed gauge\njvm_memory_total_committed 1.644478464E9\n# TYPE jvm_memory_total_init gauge\njvm_memory_total_init 1.697972224E9\n# TYPE jvm_memory_total_max gauge\njvm_memory_total_max 3.999268864E9\n# TYPE jvm_memory_total_used gauge\njvm_memory_total_used 3.82665128E8\n# TYPE jvm_thread_blocked_count gauge\njvm_thread_blocked_count 0.0\n# TYPE jvm_thread_count gauge\njvm_thread_count 82.0\n# TYPE jvm_thread_daemon_count gauge\njvm_thread_daemon_count 11.0\n# TYPE jvm_thread_deadlock_count gauge\njvm_thread_deadlock_count 0.0\n# TYPE jvm_thread_new_count gauge\njvm_thread_new_count 0.0\n# TYPE jvm_thread_runnable_count gauge\njvm_thread_runnable_count 25.0\n# TYPE jvm_thread_terminated_count gauge\njvm_thread_terminated_count 0.0\n# TYPE jvm_thread_timed_waiting_count gauge\njvm_thread_timed_waiting_count 10.0\n# TYPE jvm_thread_waiting_count gauge\njvm_thread_waiting_count 47.0\n```" - }, - { - "name": "otoroshi-protocol.md", - "id": "/topics/otoroshi-protocol.md", - "url": "/topics/otoroshi-protocol.html", - "title": "The Otoroshi communication protocol", - "content": "# The Otoroshi communication protocol\n\nThe exchange protocol secure the communication with an app. When it's enabled, Otoroshi will send for each request a value in pre-selected token header, and will check the same header in the return request.\n\n### V1 challenge\n\nIf you enable secure communication for a given service with `V1 - simple values exchange` activated, you will have to add a filter on the target application that will take the `Otoroshi-State` header and return it in a header named `Otoroshi-State-Resp`. \n\n@@@ div { .centered-img }\n\n@@@\n\nyou can find an example project that implements V1 challenge [here](https://github.com/MAIF/otoroshi/tree/master/demos/challenge)\n\n### V2 challenge\n\nIf you enable secure communication for a given service with `V2 - signed JWT token exhange` activated, you will have to add a filter on the target application that will take the `Otoroshi-State` header value containing a JWT token, verify it's content signature then extract a claim named `state` and return a new JWT token in a header named `Otoroshi-State-Resp` with the `state` value in a claim named `state-resp`. By default, the signature algorithm is HMAC+SHA512 but can you can choose your own. The sent and returned JWT tokens have short TTL to avoid being replayed. You must be validate the tokens TTL. The audience of the response token must be `Otoroshi` and you have to specify `iat`, `nbf` and `exp`.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can find an example project that implements V2 challenge [here](https://github.com/MAIF/otoroshi/tree/master/demos/challenge)\n\n### Info. token\n\nOtoroshi is also sending a JWT token in a header named `Otoroshi-Claim` that the target app can validate too.\n\nThe `Otoroshi-Claim` is a JWT token containing some informations about the service that is called and the client if available. You can choose between a legacy version of the token and a new one that is more clear and structured.\n\nBy default, the otoroshi jwt token is signed with the `otoroshi.claim.sharedKey` config property (or using the `$CLAIM_SHAREDKEY` env. variable) and uses the `HMAC512` signing algorythm. But it is possible to customize how the token is signed from the service descriptor page in the `Otoroshi exchange protocol` section. \n\n@@@ div { .centered-img }\n\n@@@\n\nusing another signing algo.\n\n@@@ div { .centered-img }\n\n@@@\n\nhere you can choose the signing algorithm and the secret/keys used. You can use syntax like `${env.MY_ENV_VAR}` or `${config.my.config.path}` to provide secret/keys values. \n\nFor example, for a service named `my-service` with a signing key `secret` with `HMAC512` signing algorythm, the basic JWT token that will be sent should look like the following\n\n```\neyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiItLSIsImF1ZCI6Im15LXNlcnZpY2UiLCJpc3MiOiJPdG9yb3NoaSIsImV4cCI6MTUyMTQ0OTkwNiwiaWF0IjoxNTIxNDQ5ODc2LCJqdGkiOiI3MTAyNWNjMTktMmFjNy00Yjk3LTljYzctMWM0ODEzYmM1OTI0In0.mRcfuFVFPLUV1FWHyL6rLHIJIu0KEpBkKQCk5xh-_cBt9cb6uD6enynDU0H1X2VpW5-bFxWCy4U4V78CbAQv4g\n```\n\nif you decode it, the payload will look something like\n\n```json\n{\n \"sub\": \"apikey_client_id\",\n \"aud\": \"my-service\",\n \"iss\": \"Otoroshi\",\n \"exp\": 1521449906,\n \"iat\": 1521449876,\n \"jti\": \"71025cc19-2ac7-4b97-9cc7-1c4813bc5924\"\n}\n```\n\nIf you want to validate the `Otoroshi-Claim` on the target app side to ensure that the input requests only comes from `Otoroshi`, you will have to write an HTTP filter to do the job. For instance, if you want to write a filter to make sure that requests only comes from Otoroshi, you can write something like the following (using playframework 2.6).\n\nScala\n: @@snip [filter.scala](../snippets/filter.scala)\n\nJava\n: @@snip [filter.java](../snippets/filter.java)\n" - }, - { - "name": "pki.md", - "id": "/topics/pki.md", - "url": "/topics/pki.html", - "title": "Otoroshi's PKI", - "content": "# Otoroshi's PKI\n\nWith Otoroshi, you can add your own certificates, your own CA and even create self signed certificates or certificates from CAs. You can enable auto renewal of thoses self signed certificates or certificates generated. Certificates have to be created with the certificate chain and the private key in PEM format.\n\nAn Otoroshi instance always starts with 5 auto-generated certificates. \n\nThe highest certificate is the **Otoroshi Default Root CA Certificate**. This certificate is used by Otoroshi to sign the intermediate CA.\n\n**Otoroshi Default Intermediate CA Certificate**: first intermediate CA that must be used to issue new certificates in Otoroshi. Creating certificates directly from the CA root certificate increases the risk of root certificate compromise, and if the CA root certificate is compromised, the entire trust infrastructure built by the SSL provider will fail\n\nThis intermediate CA signed three certificates :\n\n* **Otoroshi Default Client certificate**: \n* **Otoroshi Default Jwt Signing Keypair**: default keypair (composed of a public and private key), exposed on `https://xxxxxx/.well-known/jwks.json`, that can be used to sign and verify JWT verifier\n* **Otoroshi Default Wildcard Certificate**: this certificate has `*.oto.tools` as common name. It can be very useful to the development phase\n\n## The PKI API\n\nThe Otoroshi's PKI can be managed using the admin api of otoroshi (by default admin api is exposed on https://otoroshi-api.xxxxx)\n\nLink to the complete swagger section about PKI : https://maif.github.io/otoroshi/swagger-ui/index.html#/pki\n\n* `POST` [/api/pki/certs/_letencrypt](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genLetsEncryptCert): generates a certificate using Let's Encrypt or any ACME compatible system\n* `POST` [/api/pki/certs/_p12](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.importCertFromP12): import a .p12 file as client certificates\n* `POST` [/api/pki/certs/_valid](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.certificateIsValid): check if a certificate is valid (based on its own data)\n* `POST` [/api/pki/certs/_data](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.certificateData): extract data from a certificate\n* `POST` [/api/pki/certs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSelfSignedCert): generates a self signed certificates\n* `POST` [/api/pki/csrs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genCsr) : generates a CSR\n* `POST` [/api/pki/keys](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genKeyPair) : generates a keypair\n* `POST` [/api/pki/cas](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSelfSignedCA) : generates a self signed CA\n* `POST` [/api/pki/cas/:ca/certs/_sign](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.signCert): sign a certificate based on CSR\n* `POST` [/api/pki/cas/:ca/certs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genCert): generates a certificate\n* `POST` [/api/pki/cas/:ca/cas](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSubCA) : generates a sub-CA\n\n## The PKI UI\n\nAll generated certificates are listed in the `https://xxxxxx/bo/dashboard/certificates` page. All those certificates can be used to serve traffic with TLS, perform mTLS calls, sign and verify JWT tokens.\n\nThe PKI UI are composed of these following actions:\n\n* **Add item**: redirects the user on the certificate creation page. It’s useful when you already had a certificate (like a pem file) and that you want to load it in Otoroshi.\n* **Let's Encrypt certificate**: asks a certificate matching a given host to Let’s encrypt\n* **Create certificate**: issues a certificate with an existing Otoroshi certificate as CA. You can create a client certificate, a server certificate or a keypair certiciate that will be used to verify and sign JWT tokens.\n* **Import .p12 file**: loads a p12 file as certificate\n\nUnder these buttons, you have the list of current certificates, imported or generated, revoked or not. For each certificate, you will find: \n\n* a **name** \n* a **description** \n* the **subject** \n* the **type** of certificate (CA / client / keypair / certificate)\n* the **revoked reason** (empty if not) \n* the **creation date** following by its **expiration date**.\n\n## Exposed public keys\n\nThe Otoroshi certificate can be turned and used as keypair (simple action that can be executed by editing a certificate or during its creation, or using the admin api). A Otoroski keypair can be used to sign and verify JWT tokens with asymetric signature. Once a jwt token is signed with a keypair, it can be necessary to provide a way to the services to verify the tokens received by Otoroshi. This usage is cover by Otoroshi by the flag `Public key exposed`, available on each certificate.\n\nOtoroshi exposes each keypair with the flag enabled, on the following routes:\n\n* `https://xxxxxxxxx.xxxxxxx.xx/.well-known/otoroshi/security/jwks.json`\n* `https://otoroshi-api.xxxxxxx.xx/.well-known/jwks.json`\n\nOn these routes, you will find the list of public keys exposed using [the JWK standard](https://datatracker.ietf.org/doc/html/rfc7517)\n\n\n## OCSP Responder\n\nOtoroshi is able to revocate a certificate, directly from the UI, and to add a revocation status to specifiy the reason. The revocation reason can be :\n\n* `VALID`: The certificate is not revoked\n* `UNSPECIFIED`: Can be used to revoke certificates for reasons other than the specific codes.\n* `KEY_COMPROMISE`: It is known or suspected that the subject's private key or other aspects have been compromised.\n* `CA_COMPROMISE`: It is known or suspected that the subject's private key or other aspects have been compromised.\n* `AFFILIATION_CHANGED`: The subject's name or other information in the certificate has been modified but there is no cause to suspect that the private key has been compromised.\n* `SUPERSEDED`: The certificate has been superseded but there is no cause to suspect that the private key has been compromised\n* `CESSATION_OF_OPERATION`: The certificate is no longer needed for the purpose for which it was issued but there is no cause to suspect that the private key has been compromised\n* `CERTIFICATE_HOLD`: The certificate is temporarily revoked but there is no cause to suspect that the private kye has been compromised\n* `REMOVE_FROM_CRL`: The certificate has been unrevoked\n* `PRIVILEGE_WITH_DRAWN`: The certificate was revoked because a privilege contained within that certificate has been withdrawn\n* `AA_COMPROMISE`: It is known or suspected that aspects of the AA validated in the attribute certificate, have been compromised\n\nOtoroshi supports the Online Certificate Status Protocol for obtaining the revocation status of its certificates. The OCSP endpoint is also add to any generated certificate. This endpoint is available at `https://otoroshi-api.xxxxxx/.well-known/otoroshi/security/ocsp`\n\n## A.I.A : Authority Information Access\n\nOtoroshi provides a way to add the A.I.A in the certificate. This certificate extension contains :\n\n* Information about how to get the issuer of this certificate (CA issuer access method)\n* Address of the OCSP responder from where revocation of this certificate can be checked (OCSP access method)\n\n`https://xxxxxxxxxx/.well-known/otoroshi/security/certificates/:cert-id`" - }, - { - "name": "sessions-mgmt.md", - "id": "/topics/sessions-mgmt.md", - "url": "/topics/sessions-mgmt.html", - "title": "Sessions management", - "content": "# Sessions management\n\n## Admins\n\nAll logged users to an Otoroshi instance are administrators. An user session is created for each sucessfull connection to the UI. \n\nThese sessions are listed in the `Admin users sessions` (available in the cog icon menu or at this location of your instance `/bo/dashboard/sessions/admin`).\n\nAn admin user session is composed of: \n\n* `name`: the name of the connected user\n* `email`: the unique email\n* `Created at`: the creation date of the user session\n* `Expires at`: date until the user session is drop\n* `Profile`: user profile, at JSON format, containing name, email and others linked metadatas\n* `Rights`: list of rules to authorize the connected user on each tenant and teams.\n* `Discard session`: action to kill a session. On click, a modal will appear with the session ID\n\nIn the `Admin users sessions` page, you have two more actions:\n\n* `Discard all sessions`: kills all current sessions (including the session of the owner of this action)\n* `Discard old sessions`: kill all outdated sessions\n\n## Private apps\n\nAll logged users to a protected application has an private user session.\n\nThese sessions are listed in the `Private apps users sessions` (available in the cog icon menu or at this location of your instance `/bo/dashboard/sessions/private`).\n\nAn private user session is composed of: \n\n* `name`: the name of the connected user\n* `email`: the unique email\n* `Created at`: the creation date of the user session\n* `Expires at`: date until the user session is drop\n* `Profile`: user profile, at JSON format, containing name, email and others linked metadatas\n* `Meta.`: list of metadatas added by the authentication module.\n* `Tokens`: list of tokens received from the identity provider used. In the case of a memory authentication, this part will keep empty.\n* `Discard session`: action to kill a session. On click, a modal will appear with the session ID\n" - }, - { - "name": "tls.md", - "id": "/topics/tls.md", - "url": "/topics/tls.html", - "title": "TLS", - "content": "# TLS\n\nas you might have understand, otoroshi can store TLS certificates and use them dynamically. It means that once a certificate is imported or created in otoroshi, you can immediately use it to serve http request over TLS, to call https backends that requires mTLS or that do not have certicates signed by a globally knowned authority.\n\n## TLS termination\n\nany certficate added to otoroshi with a valid `CN` and `SANs` can be used in the following seconds to serve https requests. If you do not provide a private key with a certificate chain, the certificate will only be trusted like a CA. If you want to perform mTLS calls on you otoroshi instance, do not forget to enabled it (it is disabled by default for performance reasons as the TLS handshake is bigger with mTLS enabled)\n\n```sh\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```sh\nSSL_OUTSIDE_CLIENT_AUTH=None|Want|Need\n```\n\n### TLS termination configuration\n\nYou can configure TLS termination statically using config. file or env. variables. Everything is available at `otoroshi.tls`\n\n```conf\notoroshi {\n tls {\n # the cipher suites used by otoroshi TLS termination\n cipherSuitesJDK11 = [\"TLS_AES_128_GCM_SHA256\", \"TLS_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_RSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_RSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA\", \"TLS_EMPTY_RENEGOTIATION_INFO_SCSV\"]\n cipherSuitesJDK8 = [\"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_RSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_RSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_RSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA\", \"TLS_EMPTY_RENEGOTIATION_INFO_SCSV\"]\n cipherSuites = []\n # the protocols used by otoroshi TLS termination\n protocolsJDK11 = [\"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\"]\n protocolsJDK8 = [\"SSLv2Hello\", \"TLSv1\", \"TLSv1.1\", \"TLSv1.2\"]\n protocols = []\n # the JDK cacert access\n cacert {\n path = \"$JAVA_HOME/lib/security/cacerts\"\n password = \"changeit\"\n }\n # the mtls mode\n fromOutside {\n clientAuth = \"None\"\n clientAuth = ${?SSL_OUTSIDE_CLIENT_AUTH}\n }\n # the default trust mode\n trust {\n all = false\n all = ${?OTOROSHI_SSL_TRUST_ALL}\n }\n # some initial cacert access, useful to include non standard CA when starting (file paths)\n initialCacert = ${?CLUSTER_WORKER_INITIAL_CACERT}\n initialCacert = ${?INITIAL_CACERT}\n initialCert = ${?CLUSTER_WORKER_INITIAL_CERT}\n initialCert = ${?INITIAL_CERT}\n initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY}\n initialCertKey = ${?INITIAL_CERT_KEY}\n # initialCerts = [] \n }\n}\n```\n\n\n### TLS termination settings\n\nIt is possible to adjust the behavior of the TLS termination from the `danger zone` at the `Tls Settings` section. Here you can either define that a non-matching SNI call will use a random TLS certtificate to reply or will use a default domain (the TLS certificate associated to this domain) to reply. Here you can also choose if you want to trust all the CAs trusted by your JDK when performing TLS calls `Trust JDK CAs (client)` or when receiving mTLS calls `Trust JDK CAs (server)`. If you disable the later, it is possible to select the list of CAs presented to the client during mTLS handshake.\n\n### Certificates auto generation\n\nit is also possible to generate non-existing certificate on the fly without losing the request. If you are interested by this feature, you can enable it in the `danger zone` at the `Auto Generate Certificates` section. Here you'll have to enable it and select the CA that will generate the certificate. Of course, the client will have to trust the selected CA. You can also add filters to choose which domain are allowed to generate certificates or not. The `Reply Nicely` flag is used to reply a nice error message (ie. human readable) telling that it's not possible to have an auto certficate for the current domain. \n\n## Backends TLS and mTLS calls\n\nFor any call to a backend, it is possible to customize the TLS behavior \n\n@@@ div { .centered-img }\n\n@@@\n\nhere you can define your level of trust (trust all, loose verification) or even select on or more CAs you will trust for the following backend calls. You can also select the client certificate that will be used for the following backend calls\n\n## Keypair for signing and verification\n\nIt is also possible to use the keypair contained in a certificate to sign and verificate JWT token signature. You can mark an existing certificate in otoroshi as a keypair using the `keypair` on the certificate page.\n\n@@@ div { .centered-img }\n\n@@@\n" - }, - { - "name": "user-rights.md", - "id": "/topics/user-rights.md", - "url": "/topics/user-rights.html", - "title": "Otoroshi user rights", - "content": "# Otoroshi user rights\n\nIn Otoroshi, all users are considered **Administrators**. This choice is reinforced by the fact that Otoroshi is designed to be an administrator user interface and not an interface for users who simply want to view information. For this type of use, we encourage to use the admin API rather than giving access to the user interface.\n\nThe Otoroshi rights are split by a list of authorizations on **organizations** and **teams**. \n\nLet's taking an example where we want to authorize an administrator user on all organizations and teams.\n\nThe list of rights will be :\n\n```json\n[\n {\n \"tenant\": \"*:rw\", # (1)\n \"teams\": [\"*:rw\"] # (2)\n }\n]\n```\n\n* (1): this field, separated by a colon, indicates the name of the tenant and the associated rights. In our case, we set `*` to apply the rights to all tenants, and the `rw` to get the read and write access on them.\n* (2): the `teams` array field, represents the list of rights, applied by team. The behaviour is the same as the tenant field, we define the team or the wildcard, followed by the rights\n\nif you want to have an user that is administrator only for one organization, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\"*:rw\"]\n }\n]\n```\n\nif you want to have an user that is administrator only for two organization, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\"*:rw\"]\n },\n {\n \"tenant\": \"orga-2:rw\",\n \"teams\": [\"*:rw\"]\n }\n]\n```\n\nif you want to have an user that can only see 3 teams of one organization and one team in the other, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\n \"team-1:rw\",\n \"team-2:rw\",\n \"team-3:rw\",\n ]\n },\n {\n \"tenant\": \"orga-2:rw\",\n \"teams\": [\n \"team-4:rw\"\n ]\n }\n]\n```\n\nThe list of possible rights for an organization or a team is:\n\n* **r**: read access\n* **w**: write access\n* **not**: none access to the resource\n\nThe list of possible tenant and teams are your created tenants and teams, and the wildcard to define rights to all resources once.\n\nThe user rights is defined by the @ref:[authentication modules](../entities/auth-modules.md).\n" - } -] \ No newline at end of file diff --git a/docs/manual/content.json b/docs/manual/content.json deleted file mode 100644 index ce07289bc6..0000000000 --- a/docs/manual/content.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"about.md","id":"/about.md","url":"/about.html","title":"About Otoroshi","content":"# About Otoroshi\n\nAt the beginning of 2017, we had the need to create a new environment to be able to create new \"digital\" products very quickly in an agile fashion at @link:[MAIF](https://www.maif.fr) { open=new }. Naturally we turned to PaaS solutions and chose the excellent @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } product to run our apps. \n\nWe also chose that every feature team will have the freedom to choose its own technological stack to build its product. It was a nice move but it has also introduced some challenges in terms of homogeneity for traceability, security, logging, ... because we did not want to force library usage in the products. We could have used something like @link:[Service Mesh Pattern](http://philcalcado.com/2017/08/03/pattern_service_mesh.html) { open=new } but the deployement model of @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } prevented us to do it.\n\nThe right solution was to use a reverse proxy or some kind of API Gateway able to provide tracability, logging, security with apikeys, quotas, DNS as a service locator, etc. We needed something easy to use, with a human friendly UI, a nice API to extends its features, true hot reconfiguration, able to generate internal events for third party usage. A couple of solutions were available at that time, but not one seems to fit our needs, there was always something missing, too complicated for our needs or not playing well with @link:[Clever Cloud](https://www.clever-cloud.com) { open=new } deployment model.\n\nAt some point, we tried to write a small prototype to explore what could be our dream reverse proxy. The design was very simple, there were some rough edges but every major feature needed was there waiting to be enhanced.\n\n**Otoroshi** was born and we decided to move ahead with our hairy monster :)\n\n## Philosophy \n\nEvery OSS product build at @link:[MAIF](https://www.maif.fr) { open=new } like the develoer portal @link:[Daikoku](https://maif.github.io/daikoku) { open=new } or @link:[Izanami](https://maif.github.io/izanami) { open=new } follow a common philosophy. \n\n* the services or API provided should be **technology agnostic**.\n* **http first**: http is the right answer to the previous quote \n* **api First**: the UI is just another client of the api. \n* **secured**: the services exposed need authentication for both humans or machines \n* **event based**: the services should expose a way to get notified of what happened inside. \n"},{"name":"api.md","id":"/api.md","url":"/api.html","title":"Admin REST API","content":"# Admin REST API\n\nOtoroshi provides a fully featured REST admin API to perform almost every operation possible in the Otoroshi dashboard. The Otoroshi dashbaord is just a regular consumer of the admin API.\n\nUsing the admin API, you can do whatever you want and enhance your Otoroshi instances with a lot of features that will feet your needs.\n\n## Swagger descriptor\n\nThe Otoroshi admin API is described using OpenAPI format and is available at :\n\nhttps://maif.github.io/otoroshi/manual/code/openapi.json\n\nEvery Otoroshi instance provides its own embedded OpenAPI descriptor at :\n\nhttp://otoroshi.oto.tools:8080/api/openapi.json\n\n## Swagger documentation\n\nYou can read the OpenAPI descriptor in a more human friendly fashion using `Swagger UI`. The swagger UI documentation of the Otoroshi admin API is available at :\n\nhttps://maif.github.io/otoroshi/swagger-ui/index.html\n\nEvery Otoroshi instance provides its own embedded OpenAPI descriptor at :\n\nhttp://otoroshi.oto.tools:8080/api/swagger/ui\n\nYou can also read the swagger UI documentation of the Otoroshi admin API below :\n\n@@@ div { .swagger-frame }\n\n\n@@@\n"},{"name":"architecture.md","id":"/architecture.md","url":"/architecture.html","title":"Architecture","content":"# Architecture\n\nWhen we started the development of Otoroshi, we had several classical patterns in mind like `Service gateway`, `Service locator`, `Circuit breakers`, etc ...\n\nAt start we thought about providing a bunch of librairies that would be included in each microservice or app to perform these tasks. But the more we were thinking about it, the more it was feeling weird, unagile, etc, it also prevented us to use any technical stack we wanted to use. So we decided to change our approach to something more universal.\n\nWe chose to make Otoroshi the central part of our microservices system, something between a reverse-proxy, a service gateway and a service locator where each call to a microservice (even from another microservice) must pass through Otoroshi. There are multiple benefits to do that, each call can be logged, audited, monitored, integrated with a circuit breaker, etc without imposing libraries and technical stack. Any service is exposed through its own domain and we rely only on DNS to handle the service location part. Any access to a service is secured by default with an api key and is supervised by a circuit breaker to avoid cascading failures.\n\n@@@ div { .centered-img }\n\n@@@\n\nOtoroshi tries to embrace our @ref:[global philosophy](./about.md#philosophy) by providing a full featured REST admin api, a gorgeous admin dashboard written in @link:[React](https://reactjs.org) { open=new } that uses the api, by generating traffic events, alerts events, audit events that can be consumed by several channels. Otoroshi also supports a bunch of datastores to better match with different use cases.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"aws.md","id":"/deploy/aws.md","url":"/deploy/aws.html","title":"AWS - Elastic Beanstalk","content":"# AWS - Elastic Beanstalk\n\nNow you want to use Otoroshi on AWS. There are multiple options to deploy Otoroshi on AWS, \nfor instance :\n\n* You can deploy the @ref:[Docker image](../install/get-otoroshi.md#from-docker) on [Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n* You can create a basic [Amazon EC2](https://docs.aws.amazon.com/fr_fr/AWSEC2/latest/UserGuide/concepts.html), access it via SSH, then \ndeploy the @ref:[otoroshi.jar](../install/get-otoroshi.md#from-jar-file) \n* Or you can use [AWS Elastic Beanstalk](https://aws.amazon.com/fr/elasticbeanstalk)\n\nIn this section we are going to cover how to deploy Otoroshi on [AWS Elastic Beanstalk](https://aws.amazon.com/fr/elasticbeanstalk). \n\n## AWS Elastic Beanstalk Overview\nUnlike Clever Cloud, to deploy an application on AWS Elastic Beanstalk, you don't link your app to your VCS repository, push your code and expect it to be built and run.\n\nAWS Elastic Beanstalk does only the run part. So you have to handle your own build pipeline, upload a Zip file containing your runnable, then AWS Elastic Beanstalk will take it from there. \n \nEg: for apps running on the JVM (Scala/Java/Kotlin) a Zip with the jar inside would suffice, for apps running in a Docker container, a Zip with the DockerFile would be enough. \n\n\n## Prepare your deployment target\nActually, there are 2 options to build your target. \n\nEither you create a DockerFile from this @ref:[Docker image](../install/get-otoroshi.md#from-docker), build a zip, and do all the Otoroshi custom configuration using ENVs.\n\nOr you download the @ref:[otoroshi.jar](../install/get-otoroshi.md#from-jar-file), do all the Otoroshi custom configuration using your own otoroshi.conf, and create a DockerFile that runs the jar using your otoroshi.conf. \n\nFor the second option your DockerFile would look like this :\n\n```dockerfile\nFROM openjdk:11\nVOLUME /tmp\nEXPOSE 8080\nADD otoroshi.jar otoroshi.jar\nADD otoroshi.conf otoroshi.conf\nRUN sh -c 'touch /otoroshi.jar'\nENV JAVA_OPTS=\"\"\nENTRYPOINT [ \"sh\", \"-c\", \"java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dconfig.file=/otoroshi.conf -jar /otoroshi.jar\" ]\n``` \n \nI'd recommend the second option.\n \nNow Zip your target (Jar + Conf + DockerFile) and get ready for deployment. \n\n## Create an Otoroshi instance on AWS Elastic Beanstalk\nFirst, go to [AWS Elastic Beanstalk Console](https://eu-west-3.console.aws.amazon.com/elasticbeanstalk/home?region=eu-west-3#/welcome), don't forget to sign in and make sure that you are in the good region (eg : eu-west-3 for Paris).\n\nHit **Get started** \n\n@@@ div { .centered-img }\n\n@@@\n\nSpecify the **Application name** of your application, Otoroshi for example.\n\n@@@ div { .centered-img }\n\n@@@\n \nChoose the **Platform** of the application you want to create, in your case use Docker.\n\nFor **Application code** choose **Upload your code** then hit **Upload**.\n\n@@@ div { .centered-img }\n\n@@@\n\nBrowse the zip created in the [previous section](#prepare-your-deployment-target) from your machine. \n\nAs you can see in the image above, you can also choose an S3 location, you can imagine that at the end of your build pipeline you upload your Zip to S3, and then get it from there (I wouldn't recommend that though).\n \nWhen the upload is done, hit **Configure more options**.\n \n@@@ div { .centered-img }\n\n@@@ \n \nRight now an AWS Elastic Beanstalk application has been created, and by default an environment named Otoroshi-env is being created as well.\n\nAWS Elastic Beanstalk can manage multiple environments of the same application, for instance environments can be (prod, preprod, expriments...). \n\nOtoroshi is a bit particular, it doesn't make much sense to have multiple environments, since Otoroshi will handle all the requests from/to backend services regardless of the environment. \n \nAs you see in the image above, we are now configuring the Otoroshi-env, the one and only environment of Otoroshi.\n \nFor **Configuration presets**, choose custom configuration, now you have a load balancer for your environment with the capacity of at least one instance and at most four.\nI'd recommend at least 2 instances, to change that, on the **Capacity** card hit **Modify**. \n\n@@@ div { .centered-img }\n\n@@@\n\nChange the **Instances** to min 2, max 4 then hit **Save**. For the **Scaling triggers**, I'd keep the default values, but know that you can edit the capacity config any time you want, it only costs a redeploy, which will be done automatically by the way.\n \nInstances size is by default t2.micro, which is a bit small for running Otoroshi, I'd recommend a t2.medium. \nOn the **Instances** card hit **Modify**.\n\n@@@ div { .centered-img }\n\n@@@\n\nFor **Instance type** choose t2.medium, then hit **Save**, no need to change the volume size, unless you have a lot of http call faults, which means a lot more logs, in that case the default volume size may not be enough.\n\nThe default environment created for Otoroshi, for instance Otoroshi-env, is a web server environment which fits in your case, but the thing is that on AWS Elastic Beanstalk by default a web server environment for a docker-based application, runs behind an Nginx proxy.\nWe have to remove that proxy. So on the **Software** card hit **Modify**.\n \n@@@ div { .centered-img }\n\n@@@ \n \nFor **Proxy server** choose None then hit **Save**.\n\nAlso note that you can set Envs for Otoroshi in same page (see image below). \n\n@@@ div { .centered-img }\n\n@@@ \n\nTo finalise the creation process, hit **Create app** on the bottom right.\n\nThe Otoroshi app is now created, and it's running which is cool, but we still don't have neither a **datastore** nor **https**.\n \n## Create an Otoroshi datastore on AWS ElastiCache\n\nBy default Otoroshi uses non persistent memory to store it's data, Otoroshi supports many kinds of datastores. In this section we will be covering Redis datastore. \n\nBefore starting, using a datastore hosted by AWS is not at all mandatory, feel free to use your own if you like, but if you want to learn more about ElastiCache, this section may interest you, otherwise you can skip it.\n\nGo to [AWS ElastiCache](https://eu-west-3.console.aws.amazon.com/elasticache/home?region=eu-west-3#) and hit **Get Started Now**.\n\n@@@ div { .centered-img }\n\n@@@ \n\nFor **Cluster engine** keep Redis.\n\nChoose a **Name** for your datastore, for instance otoroshi-datastore.\n\nYou can keep all the other default values and hit **Create** on the bottom right of the page.\n\nOnce your Redis Cluster is created, it would look like the image below.\n\n@@@ div { .centered-img }\n\n@@@ \n\n\nFor applications in the same security group as your cluster, redis cluster is accessible via the **Primary Endpoint**. Don't worry the default security group is fine, you don't need any configuration to access the cluster from Otoroshi.\n\nTo make Otoroshi use the created cluster, you can either use Envs `APP_STORAGE=redis`, `REDIS_HOST` and `REDIS_PORT`, or set `otoroshi.storage=redis`, `otoroshi.redis.host` and `otoroshi.redis.port` in your otoroshi.conf.\n\n## Create SSL certificate and configure your domain\n\nOtoroshi has now a datastore, but not yet ready for use. \n\nIn order to get it ready you need to :\n\n* Configure Otoroshi with your domain \n* Create a wildcard SSL certificate for your domain\n* Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate \n* Configure your DNS to redirect all traffic on your domain to Otoroshi \n \n### Configure Otoroshi with your domain\n\nYou can use ENVs or you can use a custom otoroshi.conf in your Docker container.\n\nFor the second option your otoroshi.conf would look like this :\n\n``` \n include \"application.conf\"\n http.port = 8080\n app {\n env = \"prod\"\n domain = \"mysubdomain.oto.tools\"\n rootScheme = \"https\"\n snowflake {\n seed = 0\n }\n events {\n maxSize = 1000\n }\n backoffice {\n subdomain = \"otoroshi\"\n session {\n exp = 86400000\n }\n }\n \n storage = \"redis\"\n redis {\n host=\"myredishost\"\n port=myredisport\n }\n \n privateapps {\n subdomain = \"privateapps\"\n }\n \n adminapi {\n targetSubdomain = \"otoroshi-admin-internal-api\"\n exposedSubdomain = \"otoroshi-api\"\n defaultValues {\n backOfficeGroupId = \"admin-api-group\"\n backOfficeApiKeyClientId = \"admin-client-id\"\n backOfficeApiKeyClientSecret = \"admin-client-secret\"\n backOfficeServiceId = \"admin-api-service\"\n }\n proxy {\n https = true\n local = false\n }\n }\n claim {\n sharedKey = \"myclaimsharedkey\"\n }\n }\n \n play.http {\n session {\n secure = false\n httpOnly = true\n maxAge = 2147483646\n domain = \".mysubdomain.oto.tools\"\n cookieName = \"oto-sess\"\n }\n }\n``` \n\n### Create a wildcard SSL certificate for your domain\n\nGo to [AWS Certificate Manager](https://eu-west-3.console.aws.amazon.com/acm/home?region=eu-west-3#/firstrun).\n\nBelow **Provision certificates** hit **Get started**.\n\n@@@ div { .centered-img }\n\n@@@ \n \nKeep the default selected value **Request a public certificate** and hit **Request a certificate**.\n \n@@@ div { .centered-img }\n\n@@@ \n\nPut your **Domain name**, use *. for wildcard, for instance *\\*.mysubdomain.oto.tools*, then hit **Next**.\n\n@@@ div { .centered-img }\n\n@@@ \n\nYou can choose between **Email validation** and **DNS validation**, I'd recommend **DNS validation**, then hit **Review**. \n \n@@@ div { .centered-img }\n\n@@@ \n \nVerify that you did put the right **Domain name** then hit **Confirm and request**. \n\n@@@ div { .centered-img }\n\n@@@\n \nAs you see in the image above, to let Amazon do the validation you have to add the `CNAME` record to your DNS configuration. Normally this operation takes around one day.\n \n### Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate \n\nOnce the certificate is validated, you need to modify the configuration of Otoroshi-env to add the SSL certificate for HTTPS. \nFor that you need to go to [AWS Elastic Beanstalk applications](https://eu-west-3.console.aws.amazon.com/elasticbeanstalk/home?region=eu-west-3#/applications),\nhit **Otoroshi-env**, then on the left side hit **Configuration**, then on the **Load balancer** card hit **Modify**.\n\n@@@ div { .centered-img }\n\n@@@\n\nIn the **Application Load Balancer** section hit **Add listener**.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the popup as the image above, then hit **Add**. \n\nYou should now be seeing something like this : \n \n@@@ div { .centered-img }\n\n@@@ \n \n \nMake sure that your listener is enabled, and on the bottom right of the page hit **Apply**.\n\nNow you have **https**, so let's use Otoroshi.\n\n### Configure your DNS to redirect all traffic on your domain to Otoroshi\n \nIt's actually pretty simple, you just need to add a `CNAME` record to your DNS configuration, that redirects *\\*.mysubdomain.oto.tools* to the DNS name of Otoroshi's load balancer.\n\nTo find the DNS name of Otoroshi's load balancer go to [AWS Ec2](https://eu-west-3.console.aws.amazon.com/ec2/v2/home?region=eu-west-3#LoadBalancers:tag:elasticbeanstalk:environment-name=Otoroshi-env;sort=loadBalancerName)\n\nYou would find something like this : \n \n@@@ div { .centered-img }\n\n@@@ \n\nThere is your DNS name, so add your `CNAME` record. \n \nOnce all these steps are done, the AWS Elastic Beanstalk Otoroshi instance, would now be handling all the requests on your domain. ;) \n"},{"name":"clever-cloud.md","id":"/deploy/clever-cloud.md","url":"/deploy/clever-cloud.html","title":"Clever-Cloud","content":"# Clever-Cloud\n\nNow you want to use Otoroshi on Clever Cloud. Otoroshi has been designed and created to run on Clever Cloud and a lot of choices were made because of how Clever Cloud works.\n\n## Create an Otoroshi instance on CleverCloud\n\nIf you want to customize the configuration @ref:[use env. variables](../install/setup-otoroshi.md#configuration-with-env-variables), you can use [the example provided below](#example-of-clevercloud-env-variables)\n\nCreate a new CleverCloud app based on a clevercloud git repo (not empty) or a github project of your own (not empty).\n\n@@@ div { .centered-img }\n\n@@@\n\nThen choose what kind of app your want to create, for Otoroshi, choose `Java + Jar`\n\n@@@ div { .centered-img }\n\n@@@\n\nNext, set up choose instance size and auto-scalling. Otoroshi can run on small instances, especially if you just want to test it.\n\n@@@ div { .centered-img }\n\n@@@\n\nFinally, choose a name for your app\n\n@@@ div { .centered-img }\n\n@@@\n\nNow you just need to customize environnment variables\n\nat this point, you can also add other env. variables to configure Otoroshi like in [the example provided below](#example-of-clevercloud-env-variables)\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also use expert mode :\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, your app is ready, don't forget to add a custom domains name on the CleverCloud app matching the Otoroshi app domain. \n\n## Example of CleverCloud env. variables\n\nYou can add more env variables to customize your Otoroshi instance like the following. Use the expert mode to copy/paste all the values in one shot. If you want an real datastore, create a redis addon on clevercloud, link it to your otoroshi app and change the `APP_STORAGE` variable to `redis`\n\n
\n\n
\n```\nADMIN_API_CLIENT_ID=xxxx\nADMIN_API_CLIENT_SECRET=xxxxx\nADMIN_API_GROUP=xxxxxx\nADMIN_API_SERVICE_ID=xxxxxxx\nCLAIM_SHAREDKEY=xxxxxxx\nOTOROSHI_INITIAL_ADMIN_LOGIN=youremailaddress\nOTOROSHI_INITIAL_ADMIN_PASSWORD=yourpassword\nPLAY_CRYPTO_SECRET=xxxxxx\nSESSION_NAME=oto-session\nAPP_DOMAIN=yourdomain.tech\nAPP_ENV=prod\nAPP_STORAGE=inmemory\nAPP_ROOT_SCHEME=https\nCC_PRE_BUILD_HOOK=curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/${latest_otoroshi_version}/otoroshi.jar'\nCC_JAR_PATH=./otoroshi.jar\nCC_JAVA_VERSION=11\nPORT=8080\nSESSION_DOMAIN=.yourdomain.tech\nSESSION_MAX_AGE=604800000\nSESSION_SECURE_ONLY=true\nUSER_AGENT=otoroshi\nMAX_EVENTS_SIZE=1\nWEBHOOK_SIZE=100\nAPP_BACKOFFICE_SESSION_EXP=86400000\nAPP_PRIVATEAPPS_SESSION_EXP=86400000\nENABLE_METRICS=true\nOTOROSHI_ANALYTICS_PRESSURE_ENABLED=true\nUSE_CACHE=true\n```\n
"},{"name":"clustering.md","id":"/deploy/clustering.md","url":"/deploy/clustering.html","title":"Otoroshi clustering","content":"# Otoroshi clustering\n\nOtoroshi can work as a cluster by default as you can spin many Otoroshi servers using the same datastore or datastore cluster. In that case any instance is capable of serving services, Otoroshi admin UI, Otoroshi admin API, etc.\n\nBut sometimes, this is not enough. So Otoroshi provides an additional clustering model named `Leader / Workers` where there is a leader cluster ([control plane](https://en.wikipedia.org/wiki/Control_plane)), composed of Otoroshi instances backed by a datastore like Redis, PostgreSQL or Cassandra, that is in charge of all `writes` to the datastore through Otoroshi admin UI and API, and a worker cluster ([data plane](https://en.wikipedia.org/wiki/Forwarding_plane)) composed of horizontally scalable Otoroshi instances, backed by a super fast in memory datastore, with the sole purpose of routing traffic to your services based on data synced from the leader cluster. With this distributed Otoroshi version, you can reach your goals of high availability, scalability and security.\n\nOtoroshi clustering only uses http internally (right now) to make communications between leaders and workers instances so it is fully compatible with PaaS providers like [Clever-Cloud](https://www.clever-cloud.com/en/) that only provide one external port for http traffic.\n\n@@@ div { .centered-img }\n\n\n*Fig. 1: Simplified view*\n@@@\n\n@@@ div { .centered-img }\n\n\n*Fig. 2: Deployment view*\n@@@\n\n## Cluster configuration\n\n```hocon\notoroshi {\n cluster {\n mode = \"leader\" # can be \"off\", \"leader\", \"worker\"\n compression = 4 # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9\n leader {\n name = ${?CLUSTER_LEADER_NAME} # name of the instance, if none, it will be generated\n urls = [\"http://127.0.0.1:8080\"] # urls to contact the leader cluster\n host = \"otoroshi-api.oto.tools\" # host of the otoroshi api in the leader cluster\n clientId = \"apikey-id\" # otoroshi api client id\n clientSecret = \"secret\" # otoroshi api client secret\n cacheStateFor = 4000 # state is cached during (ms)\n }\n worker {\n name = ${?CLUSTER_WORKER_NAME} # name of the instance, if none, it will be generated\n retries = 3 # number of retries when calling leader cluster\n timeout = 2000 # timeout when calling leader cluster\n state {\n retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on state sync\n pollEvery = 10000 # interval of time (ms) between 2 state sync\n timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on state sync\n }\n quotas {\n retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on quotas sync\n pushEvery = 2000 # interval of time (ms) between 2 quotas sync\n timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on quotas sync\n }\n }\n }\n}\n```\n\nyou can also use many env. variables to configure Otoroshi cluster\n\n```hocon\notoroshi {\n cluster {\n mode = ${?CLUSTER_MODE}\n compression = ${?CLUSTER_COMPRESSION}\n leader {\n name = ${?CLUSTER_LEADER_NAME}\n host = ${?CLUSTER_LEADER_HOST}\n url = ${?CLUSTER_LEADER_URL}\n clientId = ${?CLUSTER_LEADER_CLIENT_ID}\n clientSecret = ${?CLUSTER_LEADER_CLIENT_SECRET}\n groupingBy = ${?CLUSTER_LEADER_GROUP_BY}\n cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR}\n stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH}\n }\n worker {\n name = ${?CLUSTER_WORKER_NAME}\n retries = ${?CLUSTER_WORKER_RETRIES}\n timeout = ${?CLUSTER_WORKER_TIMEOUT}\n state {\n retries = ${?CLUSTER_WORKER_STATE_RETRIES}\n pollEvery = ${?CLUSTER_WORKER_POLL_EVERY}\n timeout = ${?CLUSTER_WORKER_POLL_TIMEOUT}\n }\n quotas {\n retries = ${?CLUSTER_WORKER_QUOTAS_RETRIES}\n pushEvery = ${?CLUSTER_WORKER_PUSH_EVERY}\n timeout = ${?CLUSTER_WORKER_PUSH_TIMEOUT}\n }\n }\n }\n}\n```\n\n@@@ warning\nYou **should** use HTTPS exposition for the Otoroshi API that will be used for data sync as sensitive informations are exchanged between control plane and data plane.\n@@@\n\n@@@ warning\nYou **must** have the same cluster configuration on every Otoroshi instance (worker/leader) with only names and mode changed for each instance. Some things in leader/worker are computed using configuration of their counterpart worker/leader.\n@@@\n\n## Cluster UI\n\nOnce an Otoroshi instance is launcher as cluster Leader, a new row of live metrics tile will be available on the home page of Otoroshi admin UI.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can also access a more detailed view of the cluster at `Settings (cog icon) / Cluster View`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Run examples\n\nfor leader \n\n```sh\njava -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar\n```\n\nfor worker\n\n```sh\njava -Dhttp.port=8092 -Dhttps.port=9092 -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0=http://127.0.0.1:8091 -jar otoroshi.jar\n```\n\n## Setup a cluster by example\n\nif you want to see how to setup an otoroshi cluster, just check @ref:[the clustering tutorial](../how-to-s/setup-otoroshi-cluster.md)"},{"name":"index.md","id":"/deploy/index.md","url":"/deploy/index.html","title":"Deploy to production","content":"# Deploy to production\n\nNow it's time to deploy Otoroshi in production, in this chapter we will see what kind of things you can do.\n\nOtoroshi can run wherever you want, even on a raspberry pi (Cluster^^) ;)\n\n@@@div { .plugin .platform }\n## Clever Cloud\n\nOtoroshi provides an integration to create easily services based on application deployed on your Clever Cloud account.\n\n\n@ref:[Documentation](./clever-cloud.md)\n@@@\n\n@@@div { .plugin .platform } \n## Kubernetes\nStarting at version 1.5.0, Otoroshi provides a native Kubernetes support.\n\n\n\n@ref:[Documentation](./kubernetes.md)\n@@@\n\n@@@div { .plugin .platform } \n## AWS Elastic Beanstalk\n\nRun Otoroshi on AWS Elastic Beanstalk\n\n\n\n@ref:[Tutorial](./aws.md)\n@@@\n\n@@@div { .plugin .platform } \n## Amazon ECS\n\nDeploy the Otoroshi Docker image using Amazon Elastic Container Service\n\n\n\n@link:[Tutorial](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n\n@@@\n\n@@@div { .plugin .platform }\n## GCE\n\nDeploy the Docker image using Google Compute Engine container integration\n\n\n\n@link:[Documentation](https://cloud.google.com/compute/docs/containers/deploying-containers)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n\n@@@\n\n@@@div { .plugin .platform } \n## Azure\n\nDeploy the Docker image using Azure Container Service\n\n\n\n@link:[Documentation](https://azure.microsoft.com/en-us/services/container-service/)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker) \n@@@\n\n@@@div { .plugin .platform } \n## Heroku\n\nDeploy the Docker image using Docker integration\n\n\n\n@link:[Documentation](https://devcenter.heroku.com/articles/container-registry-and-runtime)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n@@@\n\n@@@div { .plugin .platform } \n## CloudFoundry\n\nDeploy the Docker image using -Docker integration\n\n\n\n@link:[Documentation](https://docs.cloudfoundry.org/adminguide/docker.html)\n@ref:[Docker image](../install/get-otoroshi.md#from-docker)\n@@@\n\n@@@div { .plugin .platform .platform-actions-column } \n## Your own infrastructure\n\nAs Otoroshi is a Play Framework application, you can read the doc about putting a `Play` app in production.\n\nDownload the latest Otoroshi distribution, unzip it, customize it and run it.\n\n@link:[Play Framework](https://www.playframework.com)\n@link:[Production Configuration](https://www.playframework.com/documentation/2.6.x/ProductionConfiguration)\n@ref:[Otoroshi distribution](../install/get-otoroshi.md#from-zip)\n@@@\n\n@@@div { .break }\n## Scaling and clustering in production\n@@@\n\n\n@@@div { .plugin .platform .dark-platform } \n## Clustering\n\nDeploy Otoroshi as a cluster of leaders and workers.\n\n\n@ref:[Documentation](./clustering.md)\n@@@\n\n@@@div { .plugin .platform .dark-platform } \n## Scaling Otoroshi\n\nOtoroshi is designed to be reasonably easy to scale and be highly available.\n\n\n@ref:[Documentation](./scaling.md) \n@@@\n\n@@@ index\n\n* [Clustering](./clustering.md)\n* [Kubernetes](./kubernetes.md)\n* [Clever Cloud](./clever-cloud.md)\n* [AWS - Elastic Beanstalk](./aws.md)\n* [Scaling](./scaling.md) \n\n@@@\n"},{"name":"kubernetes.md","id":"/deploy/kubernetes.md","url":"/deploy/kubernetes.html","title":"Kubernetes","content":"# Kubernetes\n\nStarting at version 1.5.0, Otoroshi provides a native Kubernetes support. Multiple otoroshi jobs (that are actually kubernetes controllers) are provided in order to\n\n- sync kubernetes secrets of type `kubernetes.io/tls` to otoroshi certificates\n- act as a standard ingress controller (supporting `Ingress` objects)\n- provide Custom Resource Definitions (CRDs) to manage Otoroshi entities from Kubernetes and act as an ingress controller with its own resources\n\n## Installing otoroshi on your kubernetes cluster\n\n@@@ warning\nYou need to have cluster admin privileges to install otoroshi and its service account, role mapping and CRDs on a kubernetes cluster. We also advise you to create a dedicated namespace (you can name it `otoroshi` for example) to install otoroshi\n@@@\n\nIf you want to deploy otoroshi into your kubernetes cluster, you can download the deployment descriptors from https://github.com/MAIF/otoroshi/tree/master/kubernetes and use kustomize to create your own overlay.\n\nYou can also create a `kustomization.yaml` file with a remote base\n\n```yaml\nbases:\n- github.com/MAIF/otoroshi/kubernetes/kustomize/overlays/simple/?ref=v1.5.11\n```\n\nThen deploy it with `kubectl apply -k ./overlays/myoverlay`. \n\nYou can also use Helm to deploy a simple otoroshi cluster on your kubernetes cluster\n\n```sh\nhelm repo add otoroshi https://maif.github.io/otoroshi/helm\nhelm install my-otoroshi otoroshi/otoroshi\n```\n\nBelow, you will find example of deployment. Do not hesitate to adapt them to your needs. Those descriptors have value placeholders that you will need to replace with actual values like \n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: ${domain}\n```\n\nyou will have to edit it to make it look like\n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: 'apis.my.domain'\n```\n\nif you don't want to use placeholders and environment variables, you can create a secret containing the configuration file of otoroshi\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: otoroshi-config\ntype: Opaque\nstringData:\n oto.conf: >\n include \"application.conf\"\n app {\n storage = \"redis\"\n domain = \"apis.my.domain\"\n }\n```\n\nand mount it in the otoroshi container\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: otoroshi-deployment\nspec:\n selector:\n matchLabels:\n run: otoroshi-deployment\n template:\n metadata:\n labels:\n run: otoroshi-deployment\n spec:\n serviceAccountName: otoroshi-admin-user\n terminationGracePeriodSeconds: 60\n hostNetwork: false\n containers:\n - image: maif/otoroshi:1.5.11\n imagePullPolicy: IfNotPresent\n name: otoroshi\n args: ['-Dconfig.file=/usr/app/otoroshi/conf/oto.conf']\n ports:\n - containerPort: 8080\n name: \"http\"\n protocol: TCP\n - containerPort: 8443\n name: \"https\"\n protocol: TCP\n volumeMounts:\n - name: otoroshi-config\n mountPath: \"/usr/app/otoroshi/conf\"\n readOnly: true\n volumes:\n - name: otoroshi-config\n secret:\n secretName: otoroshi-config\n ...\n```\n\nYou can also create several secrets for each placeholder, mount them to the otoroshi container then use their file path as value\n\n```yaml\n env:\n - name: APP_STORAGE_ROOT\n value: otoroshi\n - name: APP_DOMAIN\n value: 'file:///the/path/of/the/secret/file'\n```\n\nyou can use the same trick in the config. file itself\n\n### Note on bare metal kubernetes cluster installation\n\n@@@ note\nBare metal kubernetes clusters don't come with support for external loadbalancers (service of type `LoadBalancer`). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like [MetalLB](https://metallb.universe.tf/) that provide software `LoadBalancer` services to bare metal clusters or you can use and customize examples below.\n@@@\n\n@@@ warning\nWe don't recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.\n@@@\n\n### Common manifests\n\nthe following manifests are always needed. They create otoroshi CRDs, tokens, role, etc. Redis deployment is not mandatory, it's just an example. You can use your own existing setup.\n\nrbac.yaml\n: @@snip [rbac.yaml](../snippets/kubernetes/kustomize/base/rbac.yaml) \n\ncrds.yaml\n: @@snip [crds.yaml](../snippets/kubernetes/kustomize/base/crds.yaml) \n\nredis.yaml\n: @@snip [redis.yaml](../snippets/kubernetes/kustomize/base/redis.yaml) \n\n\n### Deploy a simple otoroshi instanciation on a cloud provider managed kubernetes cluster\n\nHere we have 2 replicas connected to the same redis instance. Nothing fancy. We use a service of type `LoadBalancer` to expose otoroshi to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the `LoadBalancer` external `CNAME` (see the example below)\n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple/deployment.yaml) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple/dns.example) \n\n### Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster\n\nHere we have 2 replicas connected to the same redis instance. Nothing fancy. The otoroshi instance are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple-baremetal/deployment.yaml) \n\nhaproxy.example\n: @@snip [haproxy.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/haproxy.example) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal/dns.example) \n\n\n### Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster using a DaemonSet\n\nHere we have one otoroshi instance on each kubernetes node (with the `otoroshi-kind: instance` label) with redis persistance. The otoroshi instances are exposed as `hostPort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/deployment.yaml) \n\nhaproxy.example\n: @@snip [haproxy.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/haproxy.example) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/simple-baremetal-daemonset/dns.example) \n\n### Deploy an otoroshi cluster on a cloud provider managed kubernetes cluster\n\nHere we have 2 replicas of an otoroshi leader connected to a redis instance and 2 replicas of an otoroshi worker connected to the leader. We use a service of type `LoadBalancer` to expose otoroshi leader/worker to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the `LoadBalancer` external `CNAME` (see the example below)\n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster/deployment.yaml) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster/dns.example) \n\n### Deploy an otoroshi cluster on a bare metal kubernetes cluster\n\nHere we have 2 replicas of otoroshi leader connected to the same redis instance and 2 replicas for otoroshi worker. The otoroshi instances are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/deployment.yaml) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/dns.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal/dns.example) \n\n### Deploy an otoroshi cluster on a bare metal kubernetes cluster using DaemonSet\n\nHere we have 1 otoroshi leader instance on each kubernetes node (with the `otoroshi-kind: leader` label) connected to the same redis instance and 1 otoroshi worker instance on each kubernetes node (with the `otoroshi-kind: worker` label). The otoroshi instances are exposed as `nodePort` so you'll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below). \n\ndeployment.yaml\n: @@snip [deployment.yaml](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/deployment.yaml) \n\nnginx.example\n: @@snip [nginx.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/nginx.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/dns.example) \n\ndns.example\n: @@snip [dns.example](../snippets/kubernetes/kustomize/overlays/cluster-baremetal-daemonset/dns.example) \n\n## Using Otoroshi as an Ingress Controller\n\nIf you want to use Otoroshi as an [Ingress Controller](https://kubernetes.io/fr/docs/concepts/services-networking/ingress/), just go to the danger zone, and in `Global scripts` add the job named `Kubernetes Ingress Controller`.\n\nThen add the following configuration for the job (with your own tweaks of course)\n\n```json\n{\n \"KubernetesConfig\": {\n \"enabled\": true,\n \"endpoint\": \"https://127.0.0.1:6443\",\n \"token\": \"eyJhbGciOiJSUzI....F463SrpOehQRaQ\",\n \"namespaces\": [\n \"*\"\n ]\n }\n}\n```\n\nthe configuration can have the following values \n\n```javascript\n{\n \"KubernetesConfig\": {\n \"endpoint\": \"https://127.0.0.1:6443\", // the endpoint to talk to the kubernetes api, optional\n \"token\": \"xxxx\", // the bearer token to talk to the kubernetes api, optional\n \"userPassword\": \"user:password\", // the user password tuple to talk to the kubernetes api, optional\n \"caCert\": \"/etc/ca.cert\", // the ca cert file path to talk to the kubernetes api, optional\n \"trust\": false, // trust any cert to talk to the kubernetes api, optional\n \"namespaces\": [\"*\"], // the watched namespaces\n \"labels\": [\"label\"], // the watched namespaces\n \"ingressClasses\": [\"otoroshi\"], // the watched kubernetes.io/ingress.class annotations, can be *\n \"defaultGroup\": \"default\", // the group to put services in otoroshi\n \"ingresses\": true, // sync ingresses\n \"crds\": false, // sync crds\n \"kubeLeader\": false, // delegate leader election to kubernetes, to know where the sync job should run\n \"restartDependantDeployments\": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments\n \"templates\": { // template for entities that will be merged with kubernetes entities. can be \"default\" to use otoroshi default templates\n \"service-group\": {},\n \"service-descriptor\": {},\n \"apikeys\": {},\n \"global-config\": {},\n \"jwt-verifier\": {},\n \"tcp-service\": {},\n \"certificate\": {},\n \"auth-module\": {},\n \"data-exporter\": {},\n \"script\": {},\n \"organization\": {},\n \"team\": {},\n \"data-exporter\": {}\n }\n }\n}\n```\n\nIf `endpoint` is not defined, Otoroshi will try to get it from `$KUBERNETES_SERVICE_HOST` and `$KUBERNETES_SERVICE_PORT`.\nIf `token` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/token`.\nIf `caCert` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`.\nIf `$KUBECONFIG` is defined, `endpoint`, `token` and `caCert` will be read from the current context of the file referenced by it.\n\nNow you can deploy your first service ;)\n\n### Deploy an ingress route\n\nnow let's say you want to deploy an http service and route to the outside world through otoroshi\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-app-deployment\nspec:\n selector:\n matchLabels:\n run: http-app-deployment\n replicas: 1\n template:\n metadata:\n labels:\n run: http-app-deployment\n spec:\n containers:\n - image: kennethreitz/httpbin\n imagePullPolicy: IfNotPresent\n name: otoroshi\n ports:\n - containerPort: 80\n name: \"http\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: http-app-service\nspec:\n ports:\n - port: 8080\n targetPort: http\n name: http\n selector:\n run: http-app-deployment\n---\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\n annotations:\n kubernetes.io/ingress.class: otoroshi\nspec:\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\nonce deployed, otoroshi will sync with kubernetes and create the corresponding service to route your app. You will be able to access your app with\n\n```sh\ncurl -X GET https://httpapp.foo.bar/get\n```\n\n### Support for Ingress Classes\n\nSince Kubernetes 1.18, you can use `IngressClass` type of manifest to specify which ingress controller you want to use for a deployment (https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#extended-configuration-with-ingress-classes). Otoroshi is fully compatible with this new manifest `kind`. To use it, configure the Ingress job to match your controller\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"ingressClasses\": [\"otoroshi.io/ingress-controller\"],\n ...\n }\n}\n```\n\nthen you have to deploy an `IngressClass` to declare Otoroshi as an ingress controller\n\n```yaml\napiVersion: \"networking.k8s.io/v1beta1\"\nkind: \"IngressClass\"\nmetadata:\n name: \"otoroshi-ingress-controller\"\nspec:\n controller: \"otoroshi.io/ingress-controller\"\n parameters:\n apiGroup: \"proxy.otoroshi.io/v1alpha\"\n kind: \"IngressParameters\"\n name: \"otoroshi-ingress-controller\"\n```\n\nand use it in your `Ingress`\n\n```yaml\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\nspec:\n ingressClassName: otoroshi-ingress-controller\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\n### Use multiple ingress controllers\n\nIt is of course possible to use multiple ingress controller at the same time (https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#using-multiple-ingress-controllers) using the annotation `kubernetes.io/ingress.class`. By default, otoroshi reacts to the class `otoroshi`, but you can make it the default ingress controller with the following config\n\n```json\n{\n \"KubernetesConfig\": {\n ...\n \"ingressClass\": \"*\",\n ...\n }\n}\n```\n\n### Supported annotations\n\nif you need to customize the service descriptor behind an ingress rule, you can use some annotations. If you need better customisation, just go to the CRDs part. The following annotations are supported :\n\n- `ingress.otoroshi.io/groups`\n- `ingress.otoroshi.io/group`\n- `ingress.otoroshi.io/groupId`\n- `ingress.otoroshi.io/name`\n- `ingress.otoroshi.io/targetsLoadBalancing`\n- `ingress.otoroshi.io/stripPath`\n- `ingress.otoroshi.io/enabled`\n- `ingress.otoroshi.io/userFacing`\n- `ingress.otoroshi.io/privateApp`\n- `ingress.otoroshi.io/forceHttps`\n- `ingress.otoroshi.io/maintenanceMode`\n- `ingress.otoroshi.io/buildMode`\n- `ingress.otoroshi.io/strictlyPrivate`\n- `ingress.otoroshi.io/sendOtoroshiHeadersBack`\n- `ingress.otoroshi.io/readOnly`\n- `ingress.otoroshi.io/xForwardedHeaders`\n- `ingress.otoroshi.io/overrideHost`\n- `ingress.otoroshi.io/allowHttp10`\n- `ingress.otoroshi.io/logAnalyticsOnServer`\n- `ingress.otoroshi.io/useAkkaHttpClient`\n- `ingress.otoroshi.io/useNewWSClient`\n- `ingress.otoroshi.io/tcpUdpTunneling`\n- `ingress.otoroshi.io/detectApiKeySooner`\n- `ingress.otoroshi.io/letsEncrypt`\n- `ingress.otoroshi.io/publicPatterns`\n- `ingress.otoroshi.io/privatePatterns`\n- `ingress.otoroshi.io/additionalHeaders`\n- `ingress.otoroshi.io/additionalHeadersOut`\n- `ingress.otoroshi.io/missingOnlyHeadersIn`\n- `ingress.otoroshi.io/missingOnlyHeadersOut`\n- `ingress.otoroshi.io/removeHeadersIn`\n- `ingress.otoroshi.io/removeHeadersOut`\n- `ingress.otoroshi.io/headersVerification`\n- `ingress.otoroshi.io/matchingHeaders`\n- `ingress.otoroshi.io/ipFiltering.whitelist`\n- `ingress.otoroshi.io/ipFiltering.blacklist`\n- `ingress.otoroshi.io/api.exposeApi`\n- `ingress.otoroshi.io/api.openApiDescriptorUrl`\n- `ingress.otoroshi.io/healthCheck.enabled`\n- `ingress.otoroshi.io/healthCheck.url`\n- `ingress.otoroshi.io/jwtVerifier.ids`\n- `ingress.otoroshi.io/jwtVerifier.enabled`\n- `ingress.otoroshi.io/jwtVerifier.excludedPatterns`\n- `ingress.otoroshi.io/authConfigRef`\n- `ingress.otoroshi.io/redirection.enabled`\n- `ingress.otoroshi.io/redirection.code`\n- `ingress.otoroshi.io/redirection.to`\n- `ingress.otoroshi.io/clientValidatorRef`\n- `ingress.otoroshi.io/transformerRefs`\n- `ingress.otoroshi.io/transformerConfig`\n- `ingress.otoroshi.io/accessValidator.enabled`\n- `ingress.otoroshi.io/accessValidator.excludedPatterns`\n- `ingress.otoroshi.io/accessValidator.refs`\n- `ingress.otoroshi.io/accessValidator.config`\n- `ingress.otoroshi.io/preRouting.enabled`\n- `ingress.otoroshi.io/preRouting.excludedPatterns`\n- `ingress.otoroshi.io/preRouting.refs`\n- `ingress.otoroshi.io/preRouting.config`\n- `ingress.otoroshi.io/issueCert`\n- `ingress.otoroshi.io/issueCertCA`\n- `ingress.otoroshi.io/gzip.enabled`\n- `ingress.otoroshi.io/gzip.excludedPatterns`\n- `ingress.otoroshi.io/gzip.whiteList`\n- `ingress.otoroshi.io/gzip.blackList`\n- `ingress.otoroshi.io/gzip.bufferSize`\n- `ingress.otoroshi.io/gzip.chunkedThreshold`\n- `ingress.otoroshi.io/gzip.compressionLevel`\n- `ingress.otoroshi.io/cors.enabled`\n- `ingress.otoroshi.io/cors.allowOrigin`\n- `ingress.otoroshi.io/cors.exposeHeaders`\n- `ingress.otoroshi.io/cors.allowHeaders`\n- `ingress.otoroshi.io/cors.allowMethods`\n- `ingress.otoroshi.io/cors.excludedPatterns`\n- `ingress.otoroshi.io/cors.maxAge`\n- `ingress.otoroshi.io/cors.allowCredentials`\n- `ingress.otoroshi.io/clientConfig.useCircuitBreaker`\n- `ingress.otoroshi.io/clientConfig.retries`\n- `ingress.otoroshi.io/clientConfig.maxErrors`\n- `ingress.otoroshi.io/clientConfig.retryInitialDelay`\n- `ingress.otoroshi.io/clientConfig.backoffFactor`\n- `ingress.otoroshi.io/clientConfig.connectionTimeout`\n- `ingress.otoroshi.io/clientConfig.idleTimeout`\n- `ingress.otoroshi.io/clientConfig.callAndStreamTimeout`\n- `ingress.otoroshi.io/clientConfig.callTimeout`\n- `ingress.otoroshi.io/clientConfig.globalTimeout`\n- `ingress.otoroshi.io/clientConfig.sampleInterval`\n- `ingress.otoroshi.io/enforceSecureCommunication`\n- `ingress.otoroshi.io/sendInfoToken`\n- `ingress.otoroshi.io/sendStateChallenge`\n- `ingress.otoroshi.io/secComHeaders.claimRequestName`\n- `ingress.otoroshi.io/secComHeaders.stateRequestName`\n- `ingress.otoroshi.io/secComHeaders.stateResponseName`\n- `ingress.otoroshi.io/secComTtl`\n- `ingress.otoroshi.io/secComVersion`\n- `ingress.otoroshi.io/secComInfoTokenVersion`\n- `ingress.otoroshi.io/secComExcludedPatterns`\n- `ingress.otoroshi.io/secComSettings.size`\n- `ingress.otoroshi.io/secComSettings.secret`\n- `ingress.otoroshi.io/secComSettings.base64`\n- `ingress.otoroshi.io/secComUseSameAlgo`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.size`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.secret`\n- `ingress.otoroshi.io/secComAlgoChallengeOtoToBack.base64`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.size`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.secret`\n- `ingress.otoroshi.io/secComAlgoChallengeBackToOto.base64`\n- `ingress.otoroshi.io/secComAlgoInfoToken.size`\n- `ingress.otoroshi.io/secComAlgoInfoToken.secret`\n- `ingress.otoroshi.io/secComAlgoInfoToken.base64`\n- `ingress.otoroshi.io/securityExcludedPatterns`\n\nfor more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html\n\nwith the previous example, the ingress does not define any apikey, so the route is public. If you want to enable apikeys on it, you can deploy the following descriptor\n\n```yaml\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n name: http-app-ingress\n annotations:\n kubernetes.io/ingress.class: otoroshi\n ingress.otoroshi.io/group: http-app-group\n ingress.otoroshi.io/forceHttps: 'true'\n ingress.otoroshi.io/sendOtoroshiHeadersBack: 'true'\n ingress.otoroshi.io/overrideHost: 'true'\n ingress.otoroshi.io/allowHttp10: 'false'\n ingress.otoroshi.io/publicPatterns: ''\nspec:\n tls:\n - hosts:\n - httpapp.foo.bar\n secretName: http-app-cert\n rules:\n - host: httpapp.foo.bar\n http:\n paths:\n - path: /\n backend:\n serviceName: http-app-service\n servicePort: 8080\n```\n\nnow you can use an existing apikey in the `http-app-group` to access your app\n\n```sh\ncurl -X GET https://httpapp.foo.bar/get -u existing-apikey-1:secret-1\n```\n\n## Use Otoroshi CRDs for a better/full integration\n\nOtoroshi provides some Custom Resource Definitions for kubernetes in order to manage Otoroshi related entities in kubernetes\n\n- `service-groups`\n- `service-descriptors`\n- `apikeys`\n- `certificates`\n- `global-configs`\n- `jwt-verifiers`\n- `auth-modules`\n- `scripts`\n- `tcp-services`\n- `data-exporters`\n- `admins`\n- `teams`\n- `organizations`\n\nusing CRDs, you will be able to deploy and manager those entities from kubectl or the kubernetes api like\n\n```sh\nsudo kubectl get apikeys --all-namespaces\nsudo kubectl get service-descriptors --all-namespaces\ncurl -X GET \\\n -H 'Authorization: Bearer eyJhbGciOiJSUzI....F463SrpOehQRaQ' \\\n -H 'Accept: application/json' -k \\\n https://127.0.0.1:6443/apis/proxy.otoroshi.io/v1alpha1/apikeys | jq\n```\n\nYou can see this as better `Ingress` resources. Like any `Ingress` resource can define which controller it uses (using the `kubernetes.io/ingress.class` annotation), you can chose another kind of resource instead of `Ingress`. With Otoroshi CRDs you can even define resources like `Certificate`, `Apikey`, `AuthModules`, `JwtVerifier`, etc. It will help you to use all the power of Otoroshi while using the deployment model of kubernetes.\n \n@@@ warning\nwhen using Otoroshi CRDs, Kubernetes becomes the single source of truth for the synced entities. It means that any value in the descriptors deployed will overrides the one in Otoroshi datastore each time it's synced. So be careful if you use the Otoroshi UI or the API, some changes in configuration may be overriden by CRDs sync job.\n@@@\n\n### Resources examples\n\ngroup.yaml\n: @@snip [group.yaml](../snippets/crds/group.yaml) \n\napikey.yaml\n: @@snip [apikey.yaml](../snippets/crds/apikey.yaml) \n\nservice-descriptor.yaml\n: @@snip [service.yaml](../snippets/crds/service-descriptor.yaml) \n\ncertificate.yaml\n: @@snip [cert.yaml](../snippets/crds/certificate.yaml) \n\njwt.yaml\n: @@snip [jwt.yaml](../snippets/crds/jwt.yaml) \n\nauth.yaml\n: @@snip [auth.yaml](../snippets/crds/auth.yaml) \n\norganization.yaml\n: @@snip [orga.yaml](../snippets/crds/organization.yaml) \n\nteam.yaml\n: @@snip [team.yaml](../snippets/crds/team.yaml) \n\n\n### Configuration\n\nTo configure it, just go to the danger zone, and in `Global scripts` add the job named `Kubernetes Otoroshi CRDs Controller`. Then add the following configuration for the job (with your own tweak of course)\n\n```json\n{\n \"KubernetesConfig\": {\n \"enabled\": true,\n \"crds\": true,\n \"endpoint\": \"https://127.0.0.1:6443\",\n \"token\": \"eyJhbGciOiJSUzI....F463SrpOehQRaQ\",\n \"namespaces\": [\n \"*\"\n ]\n }\n}\n```\n\nthe configuration can have the following values \n\n```javascript\n{\n \"KubernetesConfig\": {\n \"endpoint\": \"https://127.0.0.1:6443\", // the endpoint to talk to the kubernetes api, optional\n \"token\": \"xxxx\", // the bearer token to talk to the kubernetes api, optional\n \"userPassword\": \"user:password\", // the user password tuple to talk to the kubernetes api, optional\n \"caCert\": \"/etc/ca.cert\", // the ca cert file path to talk to the kubernetes api, optional\n \"trust\": false, // trust any cert to talk to the kubernetes api, optional\n \"namespaces\": [\"*\"], // the watched namespaces\n \"labels\": [\"label\"], // the watched namespaces\n \"ingressClasses\": [\"otoroshi\"], // the watched kubernetes.io/ingress.class annotations, can be *\n \"defaultGroup\": \"default\", // the group to put services in otoroshi\n \"ingresses\": false, // sync ingresses\n \"crds\": true, // sync crds\n \"kubeLeader\": false, // delegate leader election to kubernetes, to know where the sync job should run\n \"restartDependantDeployments\": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments\n \"templates\": { // template for entities that will be merged with kubernetes entities. can be \"default\" to use otoroshi default templates\n \"service-group\": {},\n \"service-descriptor\": {},\n \"apikeys\": {},\n \"global-config\": {},\n \"jwt-verifier\": {},\n \"tcp-service\": {},\n \"certificate\": {},\n \"auth-module\": {},\n \"data-exporter\": {},\n \"script\": {},\n \"organization\": {},\n \"team\": {},\n \"data-exporter\": {}\n }\n }\n}\n```\n\nIf `endpoint` is not defined, Otoroshi will try to get it from `$KUBERNETES_SERVICE_HOST` and `$KUBERNETES_SERVICE_PORT`.\nIf `token` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/token`.\nIf `caCert` is not defined, Otoroshi will try to get it from the file at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`.\nIf `$KUBECONFIG` is defined, `endpoint`, `token` and `caCert` will be read from the current context of the file referenced by it.\n\nyou can find a more complete example of the configuration object [here](https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/plugins/jobs/kubernetes/config.scala#L134-L163)\n\n### Note about `apikeys` and `certificates` resources\n\nApikeys and Certificates are a little bit different than the other resources. They have ability to be defined without their secret part, but with an export setting so otoroshi will generate the secret parts and export the apikey or the certificate to kubernetes secret. Then any app will be able to mount them as volumes (see the full example below)\n\nIn those resources you can define \n\n```yaml\nexportSecret: true \nsecretName: the-secret-name\n```\n\nand omit `clientSecret` for apikey or `publicKey`, `privateKey` for certificates. For certificate you will have to provide a `csr` for the certificate in order to generate it\n\n```yaml\ncsr:\n issuer: CN=Otoroshi Root\n hosts: \n - httpapp.foo.bar\n - httpapps.foo.bar\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-front, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n```\n\nwhen apikeys are exported as kubernetes secrets, they will have the type `otoroshi.io/apikey-secret` with values `clientId` and `clientSecret`\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: apikey-1\ntype: otoroshi.io/apikey-secret\ndata:\n clientId: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n clientSecret: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n```\n\nwhen certificates are exported as kubernetes secrets, they will have the type `kubernetes.io/tls` with the standard values `tls.crt` (the full cert chain) and `tls.key` (the private key). For more convenience, they will also have a `cert.crt` value containing the actual certificate without the ca chain and `ca-chain.crt` containing the ca chain without the certificate.\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: certificate-1\ntype: kubernetes.io/tls\ndata:\n tls.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n tls.key: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n cert.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==\n ca-chain.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA== \n```\n\n## Full CRD example\n\nthen you can deploy the previous example with better configuration level, and using mtls, apikeys, etc\n\nLet say the app looks like :\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\n// here we read the apikey to access http-app-2 from files mounted from secrets\nconst clientId = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientId').toString('utf8')\nconst clientSecret = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientSecret').toString('utf8')\n\nconst backendKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/tls.key').toString('utf8')\nconst backendCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/cert.crt').toString('utf8')\nconst backendCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/ca-chain.crt').toString('utf8')\n\nconst clientKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/tls.key').toString('utf8')\nconst clientCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/cert.crt').toString('utf8')\nconst clientCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/ca-chain.crt').toString('utf8')\n\nfunction callApi2() {\n return new Promise((success, failure) => {\n const options = { \n // using the implicit internal name (*.global.otoroshi.mesh) of the other service descriptor passing through otoroshi\n hostname: 'http-app-service-descriptor-2.global.otoroshi.mesh', \n port: 433, \n path: '/', \n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Otoroshi-Client-Id': clientId,\n 'Otoroshi-Client-Secret': clientSecret,\n },\n cert: clientCert,\n key: clientKey,\n ca: clientCa\n }; \n let data = '';\n const req = https.request(options, (res) => { \n res.on('data', (d) => { \n data = data + d.toString('utf8');\n }); \n res.on('end', () => { \n success({ body: JSON.parse(data), res });\n }); \n res.on('error', (e) => { \n failure(e);\n }); \n }); \n req.end();\n })\n}\n\nconst options = { \n key: backendKey, \n cert: backendCert, \n ca: backendCa, \n // we want mtls behavior\n requestCert: true, \n rejectUnauthorized: true\n}; \nhttps.createServer(options, (req, res) => { \n res.writeHead(200, {'Content-Type': 'application/json'});\n callApi2().then(resp => {\n res.write(JSON.stringify{ (\"message\": `Hello to ${req.socket.getPeerCertificate().subject.CN}`, api2: resp.body })); \n });\n}).listen(433);\n```\n\nthen, the descriptors will be :\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-app-deployment\nspec:\n selector:\n matchLabels:\n run: http-app-deployment\n replicas: 1\n template:\n metadata:\n labels:\n run: http-app-deployment\n spec:\n containers:\n - image: foo/http-app\n imagePullPolicy: IfNotPresent\n name: otoroshi\n ports:\n - containerPort: 443\n name: \"https\"\n volumeMounts:\n - name: apikey-volume\n # here you will be able to read apikey from files \n # - /var/run/secrets/kubernetes.io/apikeys/clientId\n # - /var/run/secrets/kubernetes.io/apikeys/clientSecret\n mountPath: \"/var/run/secrets/kubernetes.io/apikeys\"\n readOnly: true\n volumeMounts:\n - name: backend-cert-volume\n # here you will be able to read app cert from files \n # - /var/run/secrets/kubernetes.io/certs/backend/tls.crt\n # - /var/run/secrets/kubernetes.io/certs/backend/tls.key\n mountPath: \"/var/run/secrets/kubernetes.io/certs/backend\"\n readOnly: true\n - name: client-cert-volume\n # here you will be able to read app cert from files \n # - /var/run/secrets/kubernetes.io/certs/client/tls.crt\n # - /var/run/secrets/kubernetes.io/certs/client/tls.key\n mountPath: \"/var/run/secrets/kubernetes.io/certs/client\"\n readOnly: true\n volumes:\n - name: apikey-volume\n secret:\n # here we reference the secret name from apikey http-app-2-apikey-1\n secretName: secret-2\n - name: backend-cert-volume\n secret:\n # here we reference the secret name from cert http-app-certificate-backend\n secretName: http-app-certificate-backend-secret\n - name: client-cert-volume\n secret:\n # here we reference the secret name from cert http-app-certificate-client\n secretName: http-app-certificate-client-secret\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: http-app-service\nspec:\n ports:\n - port: 8443\n targetPort: https\n name: https\n selector:\n run: http-app-deployment\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ServiceGroup\nmetadata:\n name: http-app-group\n annotations:\n otoroshi.io/id: http-app-group\nspec:\n description: a group to hold services about the http-app\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-apikey-1\n# this apikey can be used to access the app\nspec:\n # a secret name secret-1 will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: secret-1\n authorizedEntities: \n - group_http-app-group\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-2-apikey-1\n# this apikey can be used to access another app in a different group\nspec:\n # a secret name secret-1 will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: secret-2\n authorizedEntities: \n - group_http-app-2-group\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-frontend\nspec:\n description: certificate for the http-app on otorshi frontend\n autoRenew: true\n csr:\n issuer: CN=Otoroshi Root\n hosts: \n - httpapp.foo.bar\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-front, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-backend\nspec:\n description: certificate for the http-app deployed on pods\n autoRenew: true\n # a secret name http-app-certificate-backend-secret will be created by otoroshi and can be used by containers\n exportSecret: true \n secretName: http-app-certificate-backend-secret\n csr:\n issuer: CN=Otoroshi Root\n hosts: \n - http-app-service \n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-back, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: Certificate\nmetadata:\n name: http-app-certificate-client\nspec:\n description: certificate for the http-app\n autoRenew: true\n secretName: http-app-certificate-client-secret\n csr:\n issuer: CN=Otoroshi Root\n key:\n algo: rsa\n size: 2048\n subject: UID=httpapp-client, O=OtoroshiApps\n client: false\n ca: false\n duration: 31536000000\n signatureAlg: SHA256WithRSAEncryption\n digestAlg: SHA-256\n---\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ServiceDescriptor\nmetadata:\n name: http-app-service-descriptor\nspec:\n description: the service descriptor for the http app\n groups: \n - http-app-group\n forceHttps: true\n hosts:\n - httpapp.foo.bar # hostname exposed oustide of the kubernetes cluster\n # - http-app-service-descriptor.global.otoroshi.mesh # implicit internal name inside the kubernetes cluster \n matchingRoot: /\n targets:\n - url: https://http-app-service:8443\n # alternatively, you can use serviceName and servicePort to use pods ip addresses\n # serviceName: http-app-service\n # servicePort: https\n mtlsConfig:\n # use mtls to contact the backend\n mtls: true\n certs: \n # reference the DN for the client cert\n - UID=httpapp-client, O=OtoroshiApps\n trustedCerts: \n # reference the DN for the CA cert \n - CN=Otoroshi Root\n sendOtoroshiHeadersBack: true\n xForwardedHeaders: true\n overrideHost: true\n allowHttp10: false\n publicPatterns:\n - /health\n additionalHeaders:\n x-foo: bar\n# here you can specify everything supported by otoroshi like jwt-verifiers, auth config, etc ... for more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html\n```\n\nnow with this descriptor deployed, you can access your app with a command like \n\n```sh\nCLIENT_ID=`kubectl get secret secret-1 -o jsonpath=\"{.data.clientId}\" | base64 --decode`\nCLIENT_SECRET=`kubectl get secret secret-1 -o jsonpath=\"{.data.clientSecret}\" | base64 --decode`\ncurl -X GET https://httpapp.foo.bar/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n## Expose Otoroshi to outside world\n\nIf you deploy Otoroshi on a kubernetes cluster, the Otoroshi service is deployed as a loadbalancer (service type: `LoadBalancer`). You'll need to declare in your DNS settings any name that can be routed by otoroshi going to the loadbalancer endpoint (CNAME or ip addresses) of your kubernetes distribution. If you use a managed kubernetes cluster from a cloud provider, it will work seamlessly as they will provide external loadbalancers out of the box. However, if you use a bare metal kubernetes cluster, id doesn't come with support for external loadbalancers (service of type `LoadBalancer`). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like [MetalLB](https://metallb.universe.tf/) that provide software `LoadBalancer` services to bare metal clusters or you can use and customize examples in the installation section.\n\n@@@ warning\nWe don't recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.\n@@@ \n\n## Access a service from inside the k8s cluster\n\n### Using host header overriding\n\nYou can access any service referenced in otoroshi, through otoroshi from inside the kubernetes cluster by using the otoroshi service name (if you use a template based on https://github.com/MAIF/otoroshi/tree/master/kubernetes/base deployed in the otoroshi namespace) and the host header with the service domain like :\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET -H 'Host: httpapp.foo.bar' https://otoroshi-service.otoroshi.svc.cluster.local:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using dedicated services\n\nit's also possible to define services that targets otoroshi deployment (or otoroshi workers deployment) and use then as valid hosts in otoroshi services \n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: my-awesome-service\nspec:\n selector:\n # run: otoroshi-deployment\n # or in cluster mode\n run: otoroshi-worker-deployment\n ports:\n - port: 8080\n name: \"http\"\n targetPort: \"http\"\n - port: 8443\n name: \"https\"\n targetPort: \"https\"\n```\n\nand access it like\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET https://my-awesome-service.my-namspace.svc.cluster.local:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using coredns integration\n\nYou can also enable the coredns integration to simplify the flow. You can use the the following keys in the plugin config :\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"coreDnsIntegration\": true, // enable coredns integration for intra cluster calls\n \"kubeSystemNamespace\": \"kube-system\", // the namespace where coredns is deployed\n \"corednsConfigMap\": \"coredns\", // the name of the coredns configmap\n \"otoroshiServiceName\": \"otoroshi-service\", // the name of the otoroshi service, could be otoroshi-workers-service\n \"otoroshiNamespace\": \"otoroshi\", // the namespace where otoroshi is deployed\n \"clusterDomain\": \"cluster.local\", // the domain for cluster services\n ...\n }\n}\n```\n\notoroshi will patch coredns config at startup then you can call your services like\n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\ncurl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\nBy default, all services created from CRDs service descriptors are exposed as `${service-name}.${service-namespace}.otoroshi.mesh` or `${service-name}.${service-namespace}.svc.otoroshi.local`\n\n### Using coredns with manual patching\n\nyou can also patch the coredns config manually\n\n```sh\nkubectl edit configmaps coredns -n kube-system # or your own custom config map\n```\n\nand change the `Corefile` data to add the following snippet in at the end of the file\n\n```yaml\notoroshi.mesh:53 {\n errors\n health\n ready\n kubernetes cluster.local in-addr.arpa ip6.arpa {\n pods insecure\n upstream\n fallthrough in-addr.arpa ip6.arpa\n }\n rewrite name regex (.*)\\.otoroshi\\.mesh otoroshi-worker-service.otoroshi.svc.cluster.local\n forward . /etc/resolv.conf\n cache 30\n loop\n reload\n loadbalance\n}\n```\n\nyou can also define simpler rewrite if it suits you use case better\n\n```\nrewrite name my-service.otoroshi.mesh otoroshi-worker-service.otoroshi.svc.cluster.local\n```\n\ndo not hesitate to change `otoroshi-worker-service.otoroshi` according to your own setup. If otoroshi is not in cluster mode, change it to `otoroshi-service.otoroshi`. If otoroshi is not deployed in the `otoroshi` namespace, change it to `otoroshi-service.the-namespace`, etc.\n\nBy default, all services created from CRDs service descriptors are exposed as `${service-name}.${service-namespace}.otoroshi.mesh`\n\nthen you can call your service like \n\n```sh\nCLIENT_ID=\"xxx\"\nCLIENT_SECRET=\"xxx\"\n\ncurl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u \"$CLIENT_ID:$CLIENT_SECRET\"\n```\n\n### Using old kube-dns system\n\nif your stuck with an old version of kubernetes, it uses kube-dns that is not supported by otoroshi, so you will have to provide your own coredns deployment and declare it as a stubDomain in the old kube-dns system. \n\nHere is an example of coredns deployment with otoroshi domain config\n\ncoredns.yaml\n: @@snip [coredns.yaml](../snippets/kubernetes/kustomize/base/coredns.yaml)\n\nthen you can enable the kube-dns integration in the otoroshi kubernetes job\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"kubeDnsOperatorIntegration\": true, // enable kube-dns integration for intra cluster calls\n \"kubeDnsOperatorCoreDnsNamespace\": \"otoroshi\", // namespace where coredns is installed\n \"kubeDnsOperatorCoreDnsName\": \"otoroshi-dns\", // name of the coredns service\n \"kubeDnsOperatorCoreDnsPort\": 5353, // port of the coredns service\n ...\n }\n}\n```\n\n### Using Openshift DNS operator\n\nOpenshift DNS operator does not allow to customize DNS configuration a lot, so you will have to provide your own coredns deployment and declare it as a stub in the Openshift DNS operator. \n\nHere is an example of coredns deployment with otoroshi domain config\n\ncoredns.yaml\n: @@snip [coredns.yaml](../snippets/kubernetes/kustomize/base/coredns.yaml)\n\nthen you can enable the Openshift DNS operator integration in the otoroshi kubernetes job\n\n```javascript\n{\n \"KubernetesConfig\": {\n ...\n \"openshiftDnsOperatorIntegration\": true, // enable openshift dns operator integration for intra cluster calls\n \"openshiftDnsOperatorCoreDnsNamespace\": \"otoroshi\", // namespace where coredns is installed\n \"openshiftDnsOperatorCoreDnsName\": \"otoroshi-dns\", // name of the coredns service\n \"openshiftDnsOperatorCoreDnsPort\": 5353, // port of the coredns service\n ...\n }\n}\n```\n\ndon't forget to update the otoroshi `ClusterRole`\n\n```yaml\n- apiGroups:\n - operator.openshift.io\n resources:\n - dnses\n verbs:\n - get\n - list\n - watch\n - update\n```\n\n## CRD validation in kubectl\n\nIn order to get CRD validation before manifest deployments right inside kubectl, you can deploy a validation webhook that will do the trick. Also check that you have `otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator` request sink enabled.\n\nvalidation-webhook.yaml\n: @@snip [validation-webhook.yaml](../snippets/kubernetes/kustomize/base/validation-webhook.yaml)\n\n## Easier integration with otoroshi-sidecar\n\nOtoroshi can help you to easily use existing services without modifications while gettings all the perks of otoroshi like apikeys, mTLS, exchange protocol, etc. To do so, otoroshi will inject a sidecar container in the pod of your deployment that will handle call coming from otoroshi and going to otoroshi. To enable otoroshi-sidecar, you need to deploy the following admission webhook. Also check that you have `otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector` request sink enabled.\n\nsidecar-webhook.yaml\n: @@snip [sidecar-webhook.yaml](../snippets/kubernetes/kustomize/base/sidecar-webhook.yaml)\n\nthen it's quite easy to add the sidecar, just add the following label to your pod `otoroshi.io/sidecar: inject` and some annotations to tell otoroshi what certificates and apikeys to use.\n\n```yaml\nannotations:\n otoroshi.io/sidecar-apikey: backend-apikey\n otoroshi.io/sidecar-backend-cert: backend-cert\n otoroshi.io/sidecar-client-cert: oto-client-cert\n otoroshi.io/token-secret: secret\n otoroshi.io/expected-dn: UID=oto-client-cert, O=OtoroshiApps\n```\n\nnow you can just call you otoroshi handled apis from inside your pod like `curl http://my-service.namespace.otoroshi.mesh/api` without passing any apikey or client certificate and the sidecar will handle everything for you. Same thing for call from otoroshi to your pod, everything will be done in mTLS fashion with apikeys and otoroshi exchange protocol\n\nhere is a full example\n\nsidecar.yaml\n: @@snip [sidecar.yaml](../snippets/kubernetes/kustomize/base/sidecar.yaml)\n\n@@@ warning\nPlease avoid to use port `80` for your pod as it's the default port to access otoroshi from your pod and the call will be redirect to the sidecar via an iptables rule\n@@@\n\n## Daikoku integration\n\nIt is possible to easily integrate daikoku generated apikeys without any human interaction with the actual apikey secret. To do that, create a plan in Daikoku and setup the integration mode to `Automatic`\n\n@@@ div { .centered-img }\n\n@@@\n\nthen when a user subscribe for an apikey, he will only see an integration token\n\n@@@ div { .centered-img }\n\n@@@\n\nthen just create an ApiKey manifest with this token and your good to go \n\n```yaml\napiVersion: proxy.otoroshi.io/v1alpha1\nkind: ApiKey\nmetadata:\n name: http-app-2-apikey-3\nspec:\n exportSecret: true \n secretName: secret-3\n daikokuToken: RShQrvINByiuieiaCBwIZfGFgdPu7tIJEN5gdV8N8YeH4RI9ErPYJzkuFyAkZ2xy\n```\n\n"},{"name":"scaling.md","id":"/deploy/scaling.md","url":"/deploy/scaling.html","title":"Scaling Otoroshi","content":"# Scaling Otoroshi\n\n## Using multiple instances with a front load balancer\n\nOtoroshi has been designed to work with multiple instances. If you already have an infrastructure using frontal load balancing, you just have to declare Otoroshi instances as the target of all domain names handled by Otoroshi\n\n## Using master / workers mode of Otoroshi\n\nYou can read everything about it in @ref:[the clustering section](../deploy/clustering.md) of the documentation.\n\n## Using IPVS\n\nYou can use [IPVS](https://en.wikipedia.org/wiki/IP_Virtual_Server) to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi. You can find example of configuration [here](http://www.linuxvirtualserver.org/VS-DRouting.html) \n\n## Using DNS Round Robin\n\nYou can use [DNS round robin technique](https://en.wikipedia.org/wiki/Round-robin_DNS) to declare multiple A records under the domain names handled by Otoroshi.\n\n## Using software L4/L7 load balancers\n\nYou can use software L4 load balancers like NGINX or HAProxy to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi.\n\nNGINX L7\n: @@snip [nginx-http.conf](../snippets/nginx-http.conf) \n\nNGINX L4\n: @@snip [nginx-tcp.conf](../snippets/nginx-tcp.conf) \n\nHA Proxy L7\n: @@snip [haproxy-http.conf](../snippets/haproxy-http.conf) \n\nHA Proxy L4\n: @@snip [haproxy-tcp.conf](../snippets/haproxy-tcp.conf) \n\n## Using a custom TCP load balancer\n\nYou can also use any other TCP load balancer, from a hardware box to a small js file like\n\ntcp-proxy.js\n: @@snip [tcp-proxy.js](../snippets/tcp-proxy.js) \n\ntcp-proxy.rs\n: @@snip [tcp-proxy.rs](../snippets/proxy.rs) \n\n"},{"name":"dev.md","id":"/dev.md","url":"/dev.html","title":"Developing Otoroshi","content":"# Developing Otoroshi\n\nIf you want to play with Otoroshis code, here are some tips\n\n## The tools\n\nYou will need\n\n* git\n* JDK 11\n* SBT 1.3.x\n* Node 13 + yarn 1.x\n\n## Clone the repository\n\n```sh\ngit clone https://github.com/MAIF/otoroshi.git\n```\n\nor fork otoroshi and clone your own repository.\n\n## Run otoroshi in dev mode\n\nto run otoroshi in dev mode, you'll need to run two separate process to serve the javascript UI and the server part.\n\n### Javascript side\n\njust go to `/otoroshi/javascript` and install the dependencies with\n\n```sh\nyarn install\n# or\nnpm install\n```\n\nthen run the dev server with\n\n```sh\nyarn start\n# or\nnpm run start\n```\n\n### Server side\n\nsetup SBT opts with\n\n```sh\nexport SBT_OPTS=\"-Xmx2G -Xss6M\"\n```\n\nthen just go to `/otoroshi` and run the sbt console with \n\n```sh\nsbt\n```\n\nthen in the sbt console run the following command\n\n```sh\n~run -Dotoroshi.storage=file -Dotoroshi.liveJs=true -Dhttps.port=9998 -Dotoroshi.privateapps.port=9999 -Dotoroshi.adminPassword=password -Dotoroshi.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dotoroshi.events.maxSize=0\n```\n\nor you can use the [sbt-revolver](https://github.com/spray/sbt-revolver) to run otoroshi locally for a more `prod` alike behavior (on the TLS part for instance)\n\n```sh\n~reStart\n# to pass jvm args, you can use: ~reStart --- -Dotoroshi.storage=memory ...\n```\n\nyou can now access your otoroshi instance at `http://otoroshi.oto.tools:9999`\n\n## Test otoroshi\n\nto run otoroshi test just go to `/otoroshi` and run the main test suite with\n\n```sh\nsbt 'testOnly OtoroshiTests'\n```\n\n## Create a release\n\njust go to `/otoroshi/javascript` and then build the UI\n\n```sh\nyarn install\nyarn build\n```\n\nthen go to `/otoroshi` and build the otoroshi distribution\n\n```sh\nsbt ';clean;compile;dist;assembly'\n```\n\nthe otoroshi build is waiting for you in `/otoroshi/target/scala-2.12/otoroshi.jar` or `/otoroshi/target/universal/otoroshi-1.x.x.zip`\n\n## Build the documentation\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/doc.sh all\n```\n\nThe documentation is located at `manual/target/paradox/site/main/`\n\n## Format the sources\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/fmt.sh\n```"},{"name":"apikeys.md","id":"/entities/apikeys.md","url":"/entities/apikeys.html","title":"Apikeys","content":"# Apikeys\n\nAn API key is linked to one or more service group and service descriptor to allow you to access any service descriptor linked or contained in one of the linked service group. You can, of course, create multiple API key for given service groups/service descriptors.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can found a concrete example @ref:[here](../how-to-s/secure-with-apikey.md)\n\n* `ApiKey Id`: the id is a unique random key that will represent this API key\n* `ApiKey Secret`: the secret is a random key used to validate the API key\n* `ApiKey Name`: a name for the API key, used for debug purposes\n* `ApiKey description`: a useful description for this apikey\n* `Valid until`: auto disable apikey after this date\n* `Enabled`: if the API key is disabled, then any call using this API key will fail\n* `Read only`: if the API key is in read only mode, every request done with this api key will only work for GET, HEAD, OPTIONS verbs\n* `Allow pass by clientid only`: here you allow client to only pass client id in a specific header in order to grant access to the underlying api\n* `Constrained services only`: this apikey can only be used on services using apikey routing constraints\n* `Authorized on`: the groups/services linked to this api key\n\n### Metadata and tags\n\n* `Tags`: tags attached to the api key\n* `Metadata`: metadata attached to the api key\n\n### Automatic secret rotation\n\nAPI can handle automatic secret rotation by themselves. When enabled, the rotation changes the secret every `Rotation every` duration. During the `Grace period` both secret will be usable.\n \n* `Enabled`: enabled automatic apikey secret rotation\n* `Rotation every`: rotate secrets every\n* `Grace period`: period when both secrets can be used\n* `Next client secret`: display the next generated client secret\n\n### Restrictions\n\n* `Enabled`: enable restrictions\n* `Allow last`: Otoroshi will test forbidden and notFound paths before testing allowed paths\n* `Allowed`: allowed paths\n* `Forbidden`: forbidden paths\n* `Not Found`: not found paths\n\n### Call examples\n\n* `Curl Command`: simple request with the api key passed by header\n* `Basic Auth. Header`: authorization Header with the api key as base64 encoded format\n* `Curl Command with Basic Auth. Header`: simple request with api key passed in the Authorization header as base64 format\n\n### Quotas\n\n* `Throttling quota`: the authorized number of calls per second\n* `Daily quota`: the authorized number of calls per day\n* `Monthly quota`: the authorized number of calls per month\n\n@@@ warning\n\nDaily and monthly quotas are based on the following rules :\n\n* daily quota is computed between 00h00:00.000 and 23h59:59.999 of the current day\n* monthly qutoas is computed between the first day of the month at 00h00:00.000 and the last day of the month at 23h59:59.999\n@@@\n\n### Quotas consumption\n\n* `Consumed daily calls`: the number of calls consumed today\n* `Remaining daily calls`: the remaining number of calls for today\n* `Consumed monthly calls`: the number of calls consumed this month\n* `Remaining monthly calls`: the remaining number of calls for this month\n\n"},{"name":"auth-modules.md","id":"/entities/auth-modules.md","url":"/entities/auth-modules.html","title":"Authentication modules","content":"# Authentication modules\n\nThe authentication modules are the resources to manage the the access to Otoroshi UI and to protect a service.\n\nAn authentication module can be as well use on guard to access to the Otoroshi UI as to protect an app.\n\nA `private app` is an Otoroshi service with an authentication module.\n\nThe list of supported authentication are :\n\n* `OAuth 2.0/2.1` : an authorization standard that allows a user to grant limited access to their resources on one site to another site, without having to expose their credentials\n* `OAuth 1.0a` : the original standard for access delegation\n* `In memory` : create users directly in Otoroshi with rights and metadata\n* `LDAP : Lightweight Directory Access Protocol` : connect users using a set of LDAP servers\n* `SAML V2 - Security Assertion Markup Language` : an open-standard, XML-based data format that allows businesses to communicate user authentication and authorization information to partner companies and enterprise applications their employees may use.\n\nAll authentication modules have a unique `id`, a `name` and a `description`.\n\nEach module has also the following fields : \n\n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n* `HttpOnly`: if enabled, the cookie cannot be accessed through client side script, prevent cross-site scripting (XSS) by not revealing the cookie to a third party\n* `Secure`: if enabled, avoid to include cookie in an HTTP Request without secure channel, typically HTTPs.\n* `Session max. age`: duration until the session expired\n* `User validators`: a list of validator that will check if a user that successfully logged in has the right to actually pass otoroshi based on the content of it's profile. A validator is composed of a [JSONPath](https://goessner.net/articles/JsonPath/) that will tell what to check and a value that is the expected value. The JSONPath will be applied on a document that will look like\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"randomId\": \"xxxxx\",\n \"name\": \"john.doe@otoroshi.io\",\n \"email\": \"john.doe@otoroshi.io\",\n \"authConfigId\": \"xxxxxxxx\",\n \"profile\": { // the profile shape depends heavily on the identity provider\n \"sub\": \"xxxxxx\",\n \"nickname\": \"john.doe\",\n \"name\": \"john.doe@otoroshi.io\",\n \"picture\": \"https://foo.bar/avatar.png\",\n \"updated_at\": \"2022-04-20T12:57:39.723Z\",\n \"email\": \"john.doe@otoroshi.io\",\n \"email_verified\": true,\n \"rights\": [\"one\", \"two\"]\n },\n \"token\": { // the token shape depends heavily on the identity provider\n \"access_token\": \"xxxxxx\",\n \"refresh_token\": \"yyyyyy\",\n \"id_token\": \"zzzzzz\",\n \"scope\": \"openid profile email address phone offline_access\",\n \"expires_in\": 86400,\n \"token_type\": \"Bearer\"\n },\n \"realm\": \"global-oauth-xxxxxxx\",\n \"otoroshiData\": {\n ...\n },\n \"createdAt\": 1650459462650,\n \"expiredAt\": 1650545862652,\n \"lastRefresh\": 1650459462650,\n \"metadata\": {},\n \"tags\": []\n}\n```\n\nthe expected value support some syntax tricks like \n\n* `Not(value)` on a string to check if the current value does not equals another value\n* `Regex(regex)` on a string to check if the current value matches the regex\n* `RegexNot(regex)` on a string to check if the current value does not matches the regex\n* `Wildcard(*value*)` on a string to check if the current value matches the value with wildcards\n* `WildcardNot(*value*)` on a string to check if the current value does not matches the value with wildcards\n* `Contains(value)` on a string to check if the current value contains a value\n* `ContainsNot(value)` on a string to check if the current value does not contains a value\n* `Contains(Regex(regex))` on an array to check if one of the item of the array matches the regex\n* `ContainsNot(Regex(regex))` on an array to check if one of the item of the array does not matches the regex\n* `Contains(Wildcard(*value*))` on an array to check if one of the item of the array matches the wildcard value\n* `ContainsNot(Wildcard(*value*))` on an array to check if one of the item of the array does not matches the wildcard value\n* `Contains(value)` on an array to check if the array contains a value\n* `ContainsNot(value)` on an array to check if the array does not contains a value\n\nfor instance to check if the current user has the right `two`, you can write the following validator\n\n```js\n{\n \"path\": \"$.profile.rights\",\n \"value\": \"Contains(two)\"\n}\n```\n\n## OAuth 2.0 / OIDC provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check these tutorials : @ref[Secure an app with keycloak](../how-to-s/secure-app-with-keycloak.md) or @ref[Secure an app with auth0](../how-to-s/secure-app-with-auth0.md)\n\n* `Use cookie`: If your OAuth2 provider does not support query param in redirect uri, you can use cookies instead\n* `Use json payloads`: the access token, sended to retrieve the user info, will be pass in body as JSON. If disabled, it will sended as Map.\n* `Enabled PKCE flow`: This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.\n* `Disable wildcard on redirect URIs`: As of OAuth 2.1, query parameters on redirect URIs are no longer allowed\n* `Refresh tokens`: Automatically refresh access token using the refresh token if available\n* `Read profile from token`: if enabled, the user profile will be read from the access token, otherwise the user profile will be retrieved from the user information url\n* `Super admins only`: All logged in users will have super admins rights\n* `Client ID`: a public identifier of your app\n* `Client Secret`: a secret known only to the application and the authorization server\n* `Authorize URL`: used to interact with the resource owner and get the authorization to access the protected resource\n* `Token URL`: used by the application in order to get an access token or a refresh token\n* `Introspection URL`: used to validate access tokens\n* `Userinfo URL`: used to retrieve the profile of the user\n* `Login URL`: used to redirect user to the login provider page\n* `Logout URL`: redirect uri used by the identity provider to redirect user after logging out\n* `Callback URL`: redirect uri sended to the identity provider to redirect user after successfully connecting\n* `Access token field name`: field used to search access token in the response body of the token URL call\n* `Scope`: presented scopes to the user in the consent screen. Scopes are space-separated lists of identifiers used to specify what access privileges are being requested\n* `Claims`: asked name/values pairs that contains information about a user.\n* `Name field name`: Retrieve name from token field\n* `Email field name`: Retrieve email from token field\n* `Otoroshi metadata field name`: Retrieve metadata from token field\n* `Otoroshi rights field name`: Retrieve user rights from user profile\n* `Extra metadata`: merged with the user metadata\n* `Data override`: merged with extra metadata when a user connects to a `private app`\n* `Rights override`: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.\n* `Api key metadata field name`: used to extract api key metadata from the OIDC access token \n* `Api key tags field name`: used to extract api key tags from the OIDC access token \n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n* `OIDC config url`: URI of the openid-configuration used to discovery documents. By convention, this URI ends with `.well-known/openid-configuration`\n* `Token verification`: What kind of algorithm you want to use to verify/sign your JWT token with\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: The Hmac secret\n* `Base64 encoded secret`: Is the secret encoded with base64\n* `Custom TLS Settings`: TLS settings for JWKS fetching\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `Trust all`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with JWKS server\n* `Trusted certificates`: list of trusted certificates received from JWKS server\n\n## OAuth 1.0a provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : @ref[Secure an app with OAuth 1.0a](../how-to-s/secure-with-oauth1-client.md)\n\n* `Http Method`: method used to get request token and the access token \n* `Consumer key`: the identifier portion of the client credentials (equivalent to a username)\n* `Consumer secret`: the identifier portion of the client credentials (equivalent to a password)\n* `Request Token URL`: url to retrieve the request token\n* `Authorize URL`: used to redirect user to the login page\n* `Access token URL`: used to retrieve the access token from the server\n* `Profile URL`: used to get the user profile\n* `Callback URL`: used to redirect user when successfully connecting\n* `Rights override`: override the rights of the connected user. With JSON format, each authenticated user, using email, can be associated to a list of rights on tenants and Otoroshi teams.\n\n## LDAP Authentication provider\n\nIf you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : @ref[Secure an app with LDAP](../how-to-s/secure-app-with-ldap.md)\n\n* `Basic auth.`: if enabled, user and password will be extract from the `Authorization` header as a Basic authentication. It will skipped the login Otoroshi page \n* `Allow empty password`: LDAP servers configured by default with the possibility to connect without password can be secured by this module to ensure that user provides a password\n* `Super admins only`: All logged in users will have super admins rights\n* `Extract profile`: extract LDAP profile in the Otoroshi user\n* `LDAP Server URL`: list of LDAP servers to join. Otoroshi use this list in sequence and swap to the next server, each time a server breaks in timeout\n* `Search Base`: used to global filter\n* `Users search base`: concat with search base to search users in LDAP\n* `Mapping group filter`: map LDAP groups with Otoroshi rights\n* `Search Filter`: used to filter users. *\\${username}* is replace by the email of the user and compare to the given field\n* `Admin username (bind DN)`: holds the name of the environment property for specifying the identity of the principal for authenticating the caller to the service\n* `Admin password`: holds the name of the environment property for specifying the credentials of the principal for authenticating the caller to the service\n* `Extract profile filters attributes in`: keep only attributes which are matching the regex\n* `Extract profile filters attributes not in`: keep only attributes which are not matching the regex\n* `Name field name`: Retrieve name from LDAP field\n* `Email field name`: Retrieve email from LDAP field\n* `Otoroshi metadata field name`: Retrieve metadata from LDAP field\n* `Extra metadata`: merged with the user metadata\n* `Data override`: merged with extra metadata when a user connects to a `private app`\n* `Additional rights group`: list of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.\n* `Rights override`: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.\n\n## In memory provider\n\n* `Basic auth.`: if enabled, user and password will be extract from the `Authorization` header as a Basic authentication. It will skipped the login Otoroshi page \n* `Login with WebAuthn` : enabled logging by WebAuthn\n* `Users`: list of users with *name*, *email* and *metadata*. The default password is *password*. The edit button is useful when you want to change the password of the user. The reset button reinitialize the password. \n* `Users raw`: show the registered users with their profile and their rights. You can edit directly each field, especially the rights of the user.\n\n## SAML v2 provider\n\n* `Single sign on URL`: the Identity Provider Single Sign-On URL\n* `The protocol binding for the login request`: the protocol binding for the login request\n* `Single Logout URL`: a SAML flow that allows the end-user to logout from a single session and be automatically logged out of all related sessions that were established during SSO\n* `The protocol binding for the logout request`: the protocol binding for the logout request\n* `Sign documents`: Should SAML Request be signed by Otoroshi ?\n* `Validate Assertions Signature`: Enable/disable signature validation of SAML assertions\n* `Validate assertions with Otoroshi certificate`: validate assertions with Otoroshi certificate. If disabled, the `Encryption Certificate` and `Encryption Private Key` fields can be used to pass a certificate and a private key to validate assertions.\n* `Encryption Certificate`: certificate used to verify assertions\n* `Encryption Private Key`: privaye key used to verify assertions\n* `Signing Certificate`: certicate used to sign documents\n* `Signing Private Key`: private key to sign documents\n* `Signature al`: the signature algorithm to use to sign documents\n* `Canonicalization Method`: canonicalization method for XML signatures \n* `Encryption KeyPair`: the keypair used to sign/verify assertions\n* `Name ID Format`: SP and IdP usually communicate each other about a subject. That subject should be identified through a NAME-IDentifier, which should be in some format so that It is easy for the other party to identify it based on the Format\n* `Use NameID format as email`: use NameID format as email. If disabled, the email will be search from the attributes\n* `URL issuer`: provide the URL to the IdP's who will issue the security token\n* `Validate Signature`: enable/disable signature validation of SAML responses\n* `Validate Assertions Signature`: should SAML Assertions to be decrypted ?\n* `Validating Certificates`: the certificate in PEM format that must be used to check for signatures.\n\n## Special routes\n\nwhen using private apps with auth. modules, you can access special routes that can help you \n\n```sh \nGET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/logout' # trigger logout for the current auth. module\nGET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/me' # get the current logged user profile (do not forget to pass cookies)\n```\n\n## Related pages\n* @ref[Secure an app with auth0](../how-to-s/secure-app-with-auth0.md)\n* @ref[Secure an app with keycloak](../how-to-s/secure-app-with-keycloak.md)\n* @ref[Secure an app with LDAP](../how-to-s/secure-app-with-ldap.md)\n* @ref[Secure an app with OAuth 1.0a](../how-to-s/secure-with-oauth1-client.md)"},{"name":"certificates.md","id":"/entities/certificates.md","url":"/entities/certificates.html","title":"Certificates","content":"# Certificates\n\nAll generated and imported certificates are listed in the `https://otoroshi.xxxx/bo/dashboard/certificates` page. All those certificates can be used to serve traffic with TLS, perform mTLS calls, sign and verify JWT tokens.\n\nThe list of available actions are:\n\n* `Add item`: redirects the user on the certificate creation page. It's useful when you already had a certificate (like a pem file) and that you want to load it in Otoroshi.\n* `Let's Encrypt certificate`: asks a certificate matching a given host to Let's encrypt \n* `Create certificate`: issues a certificate with an existing Otoroshi certificate as CA.\n* `Import .p12 file`: loads a p12 file as certificate\n\n## Add item\n\n* `Id`: the generated unique id of the certificate\n* `Name`: the name of the certificate\n* `Description`: the description of the certificate\n* `Auto renew cert.`: certificate will be issued when it will be expired. Only works with a CA from Otoroshi and a known private key\n* `Client cert.`: the certificate generated will be used to identicate a client to a server\n* `Keypair`: the certificate entity will be a pair of public key and private key.\n* `Public key exposed`: if true, the public key will be exposed on `http://otoroshi-api.your-domain/.well-known/jwks.json`\n* `Certificate status`: the current status of the certificate. It can be valid if the certificate is not revoked and not expired, or equal to the reason of the revocation\n* `Certificate full chain`: list of certificates used to authenticate a client or a server\n* `Certificate private key`: the private key of the certificate or nothing if wanted. You can omit it if you want just add a certificte full chain to trust them.\n* `Private key password`: the password to protect the private key\n* `Certificate tags`: the tags attached to the certificate\n* `Certaificate metadata`: the metadata attached to the certificate\n\n## Let's Encrypt certificate\n\n* `Let's encrypt`: if enabled, the certificate will be generated by Let's Encrypt. If disabled, the user will be redirect to the `Create certificate` page\n* `Host`: the host send to Let's encrypt to issue the certificate\n\n## Create certificate view\n\n* `Issuer`: the CA used to sign your certificate\n* `CA certificate`: if enabled, the certificate will be used as an authority certificate. Once generated, it will be use as CA to sign the new certificates\n* `Let's Encrypt`: redirects to the Let's Encrypt page to request a certificate\n* `Client certificate`: the certificate generated will be used to identicate a client to a server\n* `Include A.I.A`: include authority information access urls in the certificate\n* `Key Type`: the type of the private key\n* `Key Size`: the size of the private key\n* `Signature Algorithm`: the signature algorithm used to sign the certificate\n* `Digest Algorithm`: the digest algorithm used\n* `Validity`: how much time your certificate will be valid\n* `Subject DN`: the subject DN of your certificate\n* `Hosts`: the hosts of your certificate\n\n"},{"name":"data-exporters.md","id":"/entities/data-exporters.md","url":"/entities/data-exporters.html","title":"Data exporters","content":"# Data exporters\n\nThe data exporters are the way to export alerts and events from Otoroshi to an external storage.\n\nTo try them, you can folllow @ref[this tutorial](../how-to-s/export-alerts-using-mailgun.md).\n\n## Common fields\n\n* `Type`: the type of event exporter\n* `Enabled`: enabled or not the exporter\n* `Name`: given name to the exporter\n* `Description`: the data exporter description\n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n\nAll exporters are split in three parts. The first and second parts are common and the last are specific by exporter.\n\n* `Filtering and projection` : section to filter the list of sent events and alerts. The projection field allows you to export only certain event fields and reduce the size of exported data. It's composed of `Filtering` and `Projection` fields. To get a full usage of this elements, read @ref:[this section](#matching-and-projections)\n* `Queue details`: set of fields to adjust the workers of the exporter. \n * `Buffer size`: if elements are pushed onto the queue faster than the source is consumed the overflow will be handled with a strategy specified by the user. Keep in memory the number of events.\n * `JSON conversion workers`: number of workers used to transform events to JSON format in paralell\n * `Send workers`: number of workers used to send transformed events\n * `Group size`: chunk up this stream into groups of elements received within a time window (the time window is the next field)\n * `Group duration`: waiting time before sending the group of events. If the group size is reached before the group duration, the events will be instantly sent\n \nFor the last part, the `Exporter configuration` will be detail individually.\n\n## Matching and projections\n\n**Filtering** is used to **include** or **exclude** some kind of events and alerts. For each include and exclude field, you can add a list of key-value. \n\nLet's say we only want to keep Otoroshi alerts\n```json\n{ \"include\": [{ \"@type\": \"AlertEvent\" }] }\n```\n\nOtoroshi provides a list of rules to keep only events with specific values. We will use the following event to illustrate.\n\n```json\n{\n \"foo\": \"bar\",\n \"type\": \"AlertEvent\",\n \"alert\": \"big-alert\",\n \"status\": 200,\n \"codes\": [\"a\", \"b\"],\n \"inner\": {\n \"foo\": \"bar\",\n \"bar\": \"foo\"\n }\n}\n```\n\nThe rules apply with the previous example as event.\n\n@@@div { #filtering }\n \n@@@\n\n\n\n**Projection** is a list of fields to export. In the case of an empty list, all the fields of an event will be exported. In other case, **only** the listed fields will be exported.\n\nLet's say we only want to keep Otoroshi alerts and only type, timestamp and id of each exported events\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nAn other possibility is to **rename** the exported field. This value will be the same but the exported field will have a different name.\n\nLet's say we want to rename all `@id` field with `unique-id` as key\n\n```json\n{ \"@id\": \"unique-id\" }\n```\n\nThe last possiblity is to retrieve a sub-object of an event. Let's say we want to get the name of each exported user of events.\n\n```json\n{ \"user\": { \"name\": true } }\n```\n\nYou can also expand the entire source object with \n\n```json\n{\n \"$spread\": true\n}\n```\n\nand the remove fields you don't want with \n\n```json\n{\n \"fieldthatidontwant\": false\n}\n```\n\n## Elastic\n\nWith this kind of exporter, every matching event will be sent to an elastic cluster (in batch). It is quite useful and can be used in combination with [elastic read in global config](./global-config.html#analytics-elastic-dashboard-datasource-read-)\n\n* `Cluster URI`: Elastic cluster URI\n* `Index`: Elastic index \n* `Type`: Event type (not needed for elasticsearch above 6.x)\n* `User`: Elastic User (optional)\n* `Password`: Elastic password (optional)\n* `Version`: Elastic version (optional, if none provided it will be fetched from cluster)\n* `Apply template`: Automatically apply index template\n* `Check Connection`: Button to test the configuration. It will displayed a modal with checked point, and if the case of it's successfull, it will displayed the found version of the Elasticsearch and the index used\n* `Manually apply index template`: try to put the elasticsearch template by calling the api of elasticsearch\n* `Show index template`: try to retrieve the current index template presents in elasticsearch\n* `Client side temporal indexes handling`: When enabled, Otoroshi will manage the creation of indexes. When it's disabled, Otoroshi will push in the same index\n* `One index per`: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch \n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n## Webhook \n\nWith this kind of exporter, every matching event will be sent to a URL (in batch) using a POST method and an JSON array body.\n\n* `Alerts hook URL`: url used to post events\n* `Hook Headers`: headers add to the post request\n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n\n## Pulsar \n\nWith this kind of exporter, every matching event will be sent to an [Apache Pulsar topic](https://pulsar.apache.org/)\n\n\n* `Pulsar URI`: URI of the pulsar server\n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n* `Pulsar tenant`: tenant on the pulsar server\n* `Pulsar namespace`: namespace on the pulsar server\n* `Pulsar topic`: topic on the pulsar server\n\n## Kafka \n\nWith this kind of exporter, every matching event will be sent to an [Apache Kafka topic](https://kafka.apache.org/)\n\n* `Kafka Servers`: the list of servers to contact to connect the Kafka client with the Kafka cluster\n* `Kafka keypass`: the keystore password if you use a keystore/truststore to connect to Kafka cluster\n* `Kafka keystore path`: the keystore path on the server if you use a keystore/truststore to connect to Kafka cluster\n* `Kafka truststore path`: the truststore path on the server if you use a keystore/truststore to connect to Kafka cluster\n* `Custom TLS Settings`: enable the TLS configuration for the communication with Elasticsearch\n * `TLS loose`: if enabled, will block all untrustful ssl configs\n * `TrustAll`: allows any server certificates even the self-signed ones\n * `Client certificates`: list of client certificates used to communicate with elasticsearch\n * `Trusted certificates`: list of trusted certificates received from elasticsearch\n* `Kafka topic`: the topic on which Otoroshi alerts will be sent\n\n## Mailer \n\nWith this kind of exporter, every matching event will be sent in batch as an email (using one of the following email provider)\n\nOtoroshi supports 5 exporters of email type.\n\n### Console\n\nNothing to add. The events will be write on the standard output.\n\n### Generic\n\n* `Mailer url`: URL used to push events\n* `Headers`: headers add to the push requests\n* `Email addresses`: recipients of the emails\n\n### Mailgun\n\n* `EU`: is EU server ? if enabled, *https://api.eu.mailgun.net/* will be used, otherwise, the US URL will be used : *https://api.mailgun.net/*\n* `Mailgun api key`: API key of the mailgun account\n* `Mailgun domain`: domain name of the mailgun account\n* `Email addresses`: recipients of the emails\n\n### Mailjet\n\n* `Public api key`: public key of the mailjet account\n* `Private api key`: private key of the mailjet account\n* `Email addresses`: recipients of the emails\n\n### Sendgrid\n\n* `Sendgrid api key`: api key of the sendgrid account\n* `Email addresses`: recipients of the emails\n\n## File \n\n* `File path`: path where the logs will be write \n* `Max file size`: when size is reached, Otoroshi will create a new file postfixed by the current timestamp\n\n## GoReplay file\n\nWith this kind of exporter, every matching event will be sent to a `.gor` file compatible with [GoReplay](https://goreplay.org/). \n\n@@@ warning\nthis exporter will only be able to catch `TrafficCaptureEvent`. Those events are created when a route (or the global config) of the @ref:[new proxy engine](../next/engine.md) is setup to capture traffic using the `capture` flag.\n@@@\n\n* `File path`: path where the logs will be write \n* `Max file size`: when size is reached, Otoroshi will create a new file postfixed by the current timestamp\n* `Capture requests`: capture http requests in the `.gor` file\n* `Capture responses`: capture http responses in the `.gor` file\n\n## Console \n\nNothing to add. The events will be write on the standard output.\n\n## Custom \n\nThis type of exporter let you the possibility to write your own exporter with your own rules. To create an exporter, we need to navigate to the plugins page, and to create a new item of type exporter.\n\nWhen it's done, the exporter will be visible in this list.\n\n* `Exporter config.`: the configuration of the custom exporter.\n\n## Metrics \n\nThis plugin is useful to rewrite the metric labels exposed on the `/metrics` endpoint.\n\n* `Labels`: list of metric labels. Each pair contains an existing field name and the new name."},{"name":"global-config.md","id":"/entities/global-config.md","url":"/entities/global-config.html","title":"Global config","content":"# Global config\n\nThe global config, named `Danger zone` in Otoroshi, is the place to configure Otoroshi globally. \n\n> Warning: In this page, the configuration is really sensitive and affect the global behaviour of Otoroshi.\n\n\n### Misc. Settings\n\n\n* `Maintenance mode` : It pass every single service in maintenance mode. If an user calls a service, the maintenance page will be displayed\n* `No OAuth login for BackOffice` : Forces admins to login only with user/password or user/password/u2F device\n* `API Read Only`: Freeze the Otoroshi datastore in read only mode. Only people with access to the actual underlying datastore will be able to disable this.\n* `Auto link default` : When no group is specified on a service, it will be assigned to default one\n* `Use circuit breakers` : Use circuit breaker on all services\n* `Use new http client as the default Http client` : All http calls will use the new http client by default\n* `Enable live metrics` : Enable live metrics in the Otoroshi cluster. Performs a lot of writes in the datastore\n* `Digitus medius` : Use middle finger emoji as a response character for endless HTTP responses.\n* `Limit conc. req.` : Limit the number of concurrent request processed by Otoroshi to a certain amount. Highly recommended for resilience\n* `Use X-Forwarded-* headers for routing` : When evaluating routing of a request, X-Forwarded-* headers will be used if presents\n* `Max conc. req.` : Maximum number of concurrent requests processed by otoroshi.\n* `Max HTTP/1.0 resp. size` : Maximum size of an HTTP/1.0 response in bytes. After this limit, response will be cut and sent as is. The best value here should satisfy (maxConcurrentRequests * maxHttp10ResponseSize) < process.memory for worst case scenario.\n* `Max local events` : Maximum number of events stored.\n* `Lines` : *deprecated* \n\n### IP address filtering settings\n\n* `IP allowed list`: Only IP addresses that will be able to access Otoroshi exposed services\n* `IP blocklist`: IP addresses that will be refused to access Otoroshi exposed services\n* `Endless HTTP Responses`: IP addresses for which each request will return around 128 Gb of 0s\n\n\n### Quotas settings\n\n* `Global throttling`: The max. number of requests allowed per second globally on Otoroshi\n* `Throttling per IP`: The max. number of requests allowed per second per IP address globally on Otoroshi\n\n### Analytics: Elastic dashboard datasource (read)\n\n* `Cluster URI`: Elastic cluster URI\n* `Index`: Elastic index \n* `Type`: Event type (not needed for elasticsearch above 6.x)\n* `User`: Elastic User (optional)\n* `Password`: Elastic password (optional)\n* `Version`: Elastic version (optional, if none provided it will be fetched from cluster)\n* `Apply template`: Automatically apply index template\n* `Check Connection`: Button to test the configuration. It will displayed a modal with checked point, and if the case of it's successfull, it will displayed the found version of the Elasticsearch and the index used\n* `Manually apply index template`: try to put the elasticsearch template by calling the api of elasticsearch\n* `Show index template`: try to retrieve the current index template presents in elasticsearch\n* `Client side temporal indexes handling`: When enabled, Otoroshi will manage the creation of indexes. When it's disabled, Otoroshi will push in the same index\n* `One index per`: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch \n* `Custom TLS Settings`: Enable the TLS configuration for the communication with Elasticsearch\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `TrustAll`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with elasticsearch\n* `Trusted certificates`: list of trusted certificates received from elasticsearch\n\n\n### Statsd settings\n\n* `Datadog agent`: The StatsD agent is a Datadog agent\n* `StatsD agent host`: The host on which StatsD agent is listening\n* `StatsD agent port`: The port on which StatsD agent is listening (default is 8125)\n\n\n### Backoffice auth. settings\n\n* `Backoffice auth. config`: the authentication module used in front of Otoroshi. It will be used to connect to Otoroshi on the login page\n\n### Let's encrypt settings\n\n* `Enabled`: when enabled, Otoroshi will have the possiblity to sign certificate from let's encrypt notably in the SSL/TSL Certificates page \n* `Server URL`: ACME endpoint of let's encrypt \n* `Email addresses`: (optional) list of addresses used to order the certificates \n* `Contact URLs`: (optional) list of addresses used to order the certificates \n* `Public Key`: used to ask a certificate to let's encrypt, generated by Otoroshi \n* `Private Key`: used to ask a certificate to let's encrypt, generated by Otoroshi \n\n\n### CleverCloud settings\n\nOnce configured, you can register one clever cloud app of your organization directly as an Otoroshi service.\n\n* `CleverCloud consumer key`: consumer key of your clever cloud OAuth 1.0 app\n* `CleverCloud consumer secret`: consumer secret of your clever cloud OAuth 1.0 app\n* `OAuth Token`: oauth token of your clever cloud OAuth 1.0 app\n* `OAuth Secret`: oauth token secret of your clever cloud OAuth 1.0 app \n* `CleverCloud orga. Id`: id of your clever cloud organization\n\n### Global scripts\n\nGlobal scripts will be deprecated soon, please use global plugins instead (see the next section)!\n\n### Global plugins\n\n* `Enabled`: enabled all global plugins\n* `Plugins`: list of added plugins to your instance\n* `Plugin configuration`: each added plugin have a configuration that you can override from this field\n\n### Proxies\n\nIn this section, you can add a list of proxies for :\n\n* Proxy for alert emails (mailgun)\n* Proxy for alert webhooks\n* Proxy for Clever-Cloud API access\n* Proxy for services access\n* Proxy for auth. access (OAuth, OIDC)\n* Proxy for client validators\n* Proxy for JWKS access\n* Proxy for elastic access\n\nEach proxy has the following fields \n\n* `Proxy host`: host of proxy\n* `Proxy port`: port of proxy\n* `Proxy principal`: user of proxy\n* `Proxy password`: password of proxy\n* `Non proxy host`: IP address that can access the service\n\n### Quotas alerting settings\n\n* `Enable quotas exceeding alerts`: When apikey quotas is almost exceeded, an alert will be sent \n* `Daily quotas threshold`: The percentage of daily calls before sending alerts\n* `Monthly quotas threshold`: The percentage of monthly calls before sending alerts\n\n### User-Agent extraction settings\n\n* `User-Agent extraction`: Allow user-agent details extraction. Can have impact on consumed memory. \n\n### Geolocation extraction settings\n\nExtract an geolocation for each call to Otoroshi.\n\n### Tls Settings\n\n* `Use random cert.`: Use the first available cert none matches the current domain\n* `Default domain`: When the SNI domain cannot be found, this one will be used to find the matching certificate \n* `Trust JDK CAs (server)`: Trust JDK CAs. The CAs from the JDK CA bundle will be proposed in the certificate request when performing TLS handshake \n* `Trust JDK CAs (trust)`: Trust JDK CAs. The CAs from the JDK CA bundle will be used as trusted CAs when calling HTTPS resources \n* `Trusted CAs (server)`: Select the trusted CAs you want for TLS terminaison. Those CAs only will be proposed in the certificate request when performing TLS handshake \n\n\n### Auto Generate Certificates\n\n* `Enabled`: Generate certificates on the fly when they not exist\n* `Reply Nicely`: When not allowed domain name, accept connection and display a nice error message \n* `CA`: certificate CA used to generate missing certificate\n* `Allowed domains`: Allowed domains\n* `Not allowed domains`: Allowed domains\n \n\n### Global metadata\n\n* `Tags`: tags attached to the global config\n* `Metadata`: metadata attached to the global config\n\n### Actions at the bottom of the page\n\n* `Recover from a full export file`: Load global configuration from a previous export\n* `Full export`: Export with all created entities\n* `Full export (ndjson)`: Export your full state of database to ndjson format\n* `JSON`: Get the global config at JSON format \n* `YAML`: Get the global config at YAML format \n* `Enable Panic Mode`: Log out all users from UI and prevent any changes to the database by setting the admin Otoroshi api to read-only. The only way to exit of this mode is to disable this mode directly in the database. "},{"name":"index.md","id":"/entities/index.md","url":"/entities/index.html","title":"","content":"\n# Main entities\n\nIn this section, we will pass through all the main Otoroshi entities. Otoroshi entities are the main items stored in otoroshi datastore that will be used to configure routing, authentication, etc.\n\nAny entity has the following properties\n\n* `location` or `_loc`: the location of the entity (organization and team)\n* `id`: the id of the entity (except for apikeys)\n* `name`: the name of the entity\n* `description`: the description of the entity (optional)\n* `tags`: free tags that you can put on any entity to help you manage it, automate it, etc.\n* `metadata`: free key/value tuples that you can put on any entity to help you manage it, automate it, etc.\n\n@@@div { .plugin .entities }\n\n
\nOrganizations\nThis the most high level for grouping resources.\n
\n@ref:[View](./organizations.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nTeams\nOrganize your resources by teams\n
\n@ref:[View](./teams.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nService groups\nGroup your services\n
\n@ref:[View](./service-groups.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nJWT verifiers\nVerify and forge token by services.\n
\n@ref:[View](./jwt-verifiers.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nApikeys\nAdd security to your services using apikeys\n
\n@ref:[View](./apikeys.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nGlobal Config\nThe danger zone of Otoroshi\n
\n@ref:[View](./global-config.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nService descriptors\nProxy your applications with service descriptors\n
\n@ref:[View](./service-descriptors.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nTCP services\n\n
\n@ref:[View](./tcp-services.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nAuth. modules\nSecure the Otoroshi UI and your web apps\n
\n@ref:[View](./auth-modules.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nCertificates\nAdd secure communication between Otoroshi, clients and services\n
\n@ref:[View](./certificates.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nData exporters\nExport alerts, events ands logs\n
\n@ref:[View](./data-exporters.md)\n@@@\n\n@@@div { .plugin .entities }\n\n
\nScripts\n\n
\n@ref:[View](./scripts.md)\n@@@\n\n@@@ index\n\n* [Organizations](./organizations.md)\n* [Teams](./teams.md)\n* [Global Config](./global-config.md)\n* [Apikeys](./apikeys.md)\n* [Service groups](./service-groups.md)\n* [Service descriptors](./service-descriptors.md)\n* [Auth. modules](./auth-modules.md)\n* [Certificates](./certificates.md)\n* [JWT verifiers](./jwt-verifiers.md)\n* [Data exporters](./data-exporters.md)\n* [Scripts](./scripts.md)\n* [TCP services](./tcp-services.md)\n\n@@@\n"},{"name":"jwt-verifiers.md","id":"/entities/jwt-verifiers.md","url":"/entities/jwt-verifiers.html","title":"JWT verifiers","content":"# JWT verifiers\n\nSometimes, it can be pretty useful to verify Jwt tokens coming from other provider on some services. Otoroshi provides a tool to do that per service.\n\n* `Name`: name of the JWT verifier\n* `Description`: a simple description\n* `Strict`: if not strict, request without JWT token will be allowed to pass. This option is helpful when you want to force the presence of tokens in each request on a specific service \n* `Tags`: list of tags associated to the module\n* `Metadata`: list of metadata associated to the module\n\nEach JWT verifier is configurable in three steps : the `location` where find the token in incoming requests, the `validation` step to check the signature and the presence of claims in tokens, and the last step, named `Strategy`.\n\n## Token location\n\nAn incoming token can be found in three places.\n\n#### In query string\n\n* `Source`: JWT token location in query string\n* `Query param name`: the name of the query param where JWT is located\n\n#### In a header\n\n* `Source`: JWT token location in a header\n* `Header name`: the name of the header where JWT is located\n* `Remove value`: when the token is read, this value will be remove of header value (example: if the header value is *Bearer xxxx*, the *remove value* could be Bearer  don't forget the space at the end of the string)\n\n#### In a cookie\n\n* `Source`: JWT token location in a cookie\n* `Cookie name`: the name of the cookie where JWT is located\n\n## Token validation\n\nThis section is used to verify the extracted token from specified location.\n\n* `Algo.`: What kind of algorithm you want to use to verify/sign your JWT token with\n\nAccording to the selected algorithm, the validation form will change.\n\n#### Hmac + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: used to verify the token\n* `Base64 encoded secret`: if enabled, the extracted token will be base64 decoded before it is verifier\n\n#### RSASSA-PKCS1 + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Public key`: the RSA public key\n* `Private key`: the RSA private key that can be empty if not used for JWT token signing\n\n#### ECDSA + SHA\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Public key`: the ECDSA public key\n* `Private key`: the ECDSA private key that can be empty if not used for JWT token signing\n\n#### RSASSA-PKCS1 + SHA from KeyPair\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `KeyPair`: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page\n \n#### ECDSA + SHA from KeyPair\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `KeyPair`: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page\n\n#### Otoroshi KeyPair from token kid (only for verification)\n* `Use only exposed keypairs`: if enabled, Otoroshi will only use the key pairs that are exposed on the well-known. If disabled, it will search on any registered key pairs.\n\n#### JWK Set (only for verification)\n\n* `URL`: the JWK set URL where the public keys are exposed\n* `HTTP call timeout`: timeout for fetching the keyset\n* `TTL`: cache TTL for the keyset\n* `HTTP Headers`: the HTTP headers passed\n* `Key type`: type of the key searched in the jwks\n\n*TLS settings for JWKS fetching*\n\n* `Custom TLS Settings`: TLS settings for JWKS fetching\n* `TLS loose`: if enabled, will block all untrustful ssl configs\n* `Trust all`: allows any server certificates even the self-signed ones\n* `Client certificates`: list of client certificates used to communicate with JWKS server\n* `Trusted certificates`: list of trusted certificates received from JWKS server\n\n*Proxy*\n\n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n\n## Strategy\n\nThe first step is to select the verifier strategy. Otoroshi supports 4 types of JWT verifiers:\n\n* `Default JWT token` will add a token if no present. \n* `Verify JWT token` will only verifiy token signing and fields values if provided. \n* `Verify and re-sign JWT token` will verify the token and will re-sign the JWT token with the provided algo. settings. \n* `Verify, re-sign and transform JWT token` will verify the token, re-sign and will be able to transform the token.\n\nAll verifiers has the following properties: \n\n* `Verify token fields`: when the JWT token is checked, each field specified here will be verified with the provided value\n* `Verify token array value`: when the JWT token is checked, each field specified here will be verified if the provided value is contained in the array\n\n\n#### Default JWT token\n\n* `Strict`: if token is already present, the call will fail\n* `Default value`: list of claims of the generated token. These fields support raw values or language expressions. See the documentation about @ref:[the expression language](../topics/expression-language.md)\n\n#### Verify JWT token\n\nNo specific values needed. This kind of verifier needs only the two fields `Verify token fields` and `Verify token array value`.\n\n#### Verify and re-sign JWT token\n\nWhen `Verify and re-sign JWT token` is chosen, the `Re-sign settings` appear. All fields of `Re-sign settings` are the same of the `Token validation` section. The only difference is that the values are used to sign the new token and not to validate the token.\n\n\n#### Verify, re-sign and transform JWT token\n\nWhen `Verify, re-sign and transform JWT token` is chosen, the `Re-sign settings` and `Transformation settings` appear.\n\nThe `Re-sign settings` are used to sign the new token and has the same fields than the `Token validation` section.\n\nFor the `Transformation settings` section, the fields are:\n\n* `Token location`: the location where to find/set the JWT token\n* `Header name`: the name of the header where JWT is located\n* `Prepend value`: remove a value inside the header value\n* `Rename token fields`: when the JWT token is transformed, it is possible to change a field name, just specify origin field name and target field name\n* `Set token fields`: when the JWT token is transformed, it is possible to add new field with static values, just specify field name and value\n* `Remove token fields`: when the JWT token is transformed, it is possible to remove fields"},{"name":"organizations.md","id":"/entities/organizations.md","url":"/entities/organizations.html","title":"Organizations","content":"# Organizations\n\nThe resources of Otoroshi are grouped by `Organization`. This the highest level for grouping resources.\n\nAn organization have a unique `id`, a `name` and a `description`. As all Otoroshi resources, an Organization have a list of tags and metadata associated.\n\nFor example, you can use the organizations as a mean of :\n\n* to seperate resources by services or entities in your enterprise\n* to split internal and external usage of the resources (it's useful when you have a list of services deployed in your company and another one deployed by your partners)\n\n@@@ div { .centered-img }\n\n@@@\n\n## Access to the list of organizations\n\nTo visualize and edit the list of organizations, you can navigate to your instance on the `https://otoroshi.xxxxxx/bo/dashboard/organizations` route or click on the cog icon and select the organizations button.\n\nOnce on the page, you can create a new item, edit an existing organization or delete an existing one.\n\n> When an organization is deleted, the resources associated are not deleted. On the other hand, the organization and the team of associated resources are let empty.\n\n## Entities location\n\nAny otoroshi entity has a location property (`_loc` when serialized to json) explaining where and by whom the entity can be seen. \n\nAn entity can be part of one organization (`tenant` in the json document)\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": ...\n }\n ...\n}\n```\n\nor all organizations\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"*\",\n \"teams\": ...\n }\n ...\n}\n```\n\n"},{"name":"scripts.md","id":"/entities/scripts.md","url":"/entities/scripts.html","title":"Scripts","content":"# Scripts\n\nScript are a way to create plugins for otoroshi without deploying them as jar files. With scripts, you just have to store the scala code of your plugins inside the otoroshi datastore and otoroshi will compile and deploy them at startup. You can find all your scripts in the UI at `cog icon / Plugins`. You can find all the documentation about plugins @ref:[here](../plugins/index.md)\n\n@@@ warning\nThe compilation of your plugins can be pretty long and resources consuming. As the compilation happens during otoroshi boot sequence, your instance will be blocked until all plugins have compiled. This behavior can be disabled. If so, the plugins will not work until they have been compiled. Any service using a plugin that is not compiled yet will fail\n@@@\n\nLike any entity, the script has has the following properties\n\n* `id`\n* `plugin name`\n* `plugin description`\n* `tags`\n* `metadata`\n\nAnd you also have\n\n* `type`: the kind of plugin you are building with this script\n* `plugin code`: the code for your plugin\n\n## Compile\n\nYou can use the compile button to check if the code you write in `plugin code` is valid. It will automatically save your script and try to compile. As mentionned earlier, script compilation is quite resource intensive. It will affect your CPU load and your memory consumption. Don't forget to adjust your VM settings accordingly.\n"},{"name":"service-descriptors.md","id":"/entities/service-descriptors.md","url":"/entities/service-descriptors.html","title":"Service descriptors","content":"# Service descriptors\n\nServices or service descriptor, let you declare how to proxy a call from a domain name to another domain name (or multiple domain names). \n\n@@@ div { .centered-img }\n\n@@@\n\nLet’s say you have an API exposed on http://192.168.0.42 and I want to expose it on https://my.api.foo. Otoroshi will proxy all calls to https://my.api.foo and forward them to http://192.168.0.42. While doing that, it will also log everyhting, control accesses, etc.\n\n\n* `Id`: a unique random string to identify your service\n* `Groups`: each service descriptor is attached to a group. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group.\n* `Create a new group`: you can create a new group to host this descriptor\n* `Create dedicated group`: you can create a new group with an auto generated name to host this descriptor\n* `Name`: the name of your service. Only for debug and human readability purposes.\n* `Description`: the description of your service. Only for debug and human readability purposes.\n* `Service enabled`: activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist.\n* `Read only mode`: authorize only GET, HEAD, OPTIONS calls on this service\n* `Maintenance mode`: display a maintainance page when a user try to use the service\n* `Construction mode`: display a construction page when a user try to use the service\n* `Log analytics`: Log analytics events for this service on the servers\n* `Use new http client`: will use Akka Http Client for every request\n* `Detect apikey asap`: If the service is public and you provide an apikey, otoroshi will detect it and validate it. Of course this setting may impact performances because of useless apikey lookups.\n* `Send Otoroshi headers back`: when enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc ...\n* `Override Host header`: when enabled, Otoroshi will automatically set the Host header to corresponding target host\n* `Send X-Forwarded-* headers`: when enabled, Otoroshi will send X-Forwarded-* headers to target\n* `Force HTTPS`: will force redirection to `https://` if not present\n* `Allow HTTP/1.0 requests`: will return an error on HTTP/1.0 request\n* `Use new WebSocket client`: will use the new websocket client for every websocket request\n* `TCP/UDP tunneling`: with this setting enabled, otoroshi will not proxy http requests anymore but instead will create a secured tunnel between a cli on your machine and otoroshi to proxy any tcp connection with all otoroshi security features enabled\n\n### Service exposition settings\n\n* `Exposed domain`: the domain used to expose your service. Should follow pattern: `(http|https)://subdomain?.env?.domain.tld?/root?` or regex `(http|https):\\/\\/(.*?)\\.?(.*?)\\.?(.*?)\\.?(.*)\\/?(.*)`\n* `Legacy domain`: use `domain`, `subdomain`, `env` and `matchingRoot` for routing in addition to hosts, or just use hosts.\n* `Strip path`: when matching, strip the matching prefix from the upstream request URL. Defaults to true\n* `Issue Let's Encrypt cert.`: automatically issue and renew let's encrypt certificate based on domain name. Only if Let's Encrypt enabled in global config.\n* `Issue certificate`: automatically issue and renew a certificate based on domain name\n* `Possible hostnames`: all the possible hostnames for your service\n* `Possible matching paths`: all the possible matching paths for your service\n\n### Redirection\n\n* `Redirection enabled`: enabled the redirection. If enabled, a call to that service will redirect to the chosen URL\n* `Http redirection code`: type of redirection used\n* `Redirect to`: URL used to redirect user when the service is called\n\n### Service targets\n\n* `Redirect to local`: if you work locally with Otoroshi, you may want to use that feature to redirect one specific service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests\n* `Load balancing`: the load balancing algorithm used\n* `Targets`: the list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures\n* `Targets root`: Otoroshi will append this root to any target choosen. If the specified root is `/api/foo`, then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar\n\n### URL Patterns\n\n* `Make service a 'public ui'`: add a default pattern as public routes\n* `Make service a 'private api'`: add a default pattern as private routes\n* `Public patterns`: by default, every services are private only and you'll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use `/.*`\n* `Private patterns`: if you define a public pattern that is a little bit too much, you can make some of public URL private again\n\n### Restrictions\n\n* `Enabled`: enable restrictions\n* `Allow last`: Otoroshi will test forbidden and notFound paths before testing allowed paths\n* `Allowed`: allowed paths\n* `Forbidden`: forbidden paths\n* `Not Found`: not found paths\n\n### Otoroshi exchange protocol\n\n* `Enabled`: when enabled, Otoroshi will try to exchange headers with backend service to ensure no one else can use the service from outside.\n* `Send challenge`: when disbaled, Otoroshi will not check if target service respond with sent random value.\n* `Send info. token`: when enabled, Otoroshi add an additional header containing current call informations\n* `Challenge token version`: version the otoroshi exchange protocol challenge. This option will be set to V2 in a near future.\n* `Info. token version`: version the otoroshi exchange protocol info token. This option will be set to Latest in a near future.\n* `Tokens TTL`: the number of seconds for tokens (state and info) lifes\n* `State token header name`: the name of the header containing the state token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.state)\n* `State token response header name`: the name of the header containing the state response token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.stateresp)\n* `Info token header name`: the name of the header containing the info token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.claim)\n* `Excluded patterns`: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n* `Use same algo.`: when enabled, all JWT token in this section will use the same signing algorithm. If `use same algo.` is disabled, three more options will be displayed to select an algorithm for each step of the calls :\n * Otoroshi to backend\n * Backend to otoroshi\n * Info. token\n\n* `Algo.`: What kind of algorithm you want to use to verify/sign your JWT token with\n* `SHA Size`: Word size for the SHA-2 hash function used\n* `Hmac secret`: used to verify the token\n* `Base64 encoded secret`: if enabled, the extracted token will be base64 decoded before it is verifier\n\n### Authentication\n\n* `Enforce user authentication`: when enabled, user will be allowed to use the service (UI) only if they are registered users of the chosen authentication module.\n* `Auth. config`: authentication module used to protect the service\n* `Create a new auth config.`: navigate to the creation of authentication module page\n* `all auth config.`: navigate to the authentication pages\n\n* `Excluded patterns`: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n* `Strict mode`: strict mode enabled\n\n### Api keys constraints\n\n* `From basic auth.`: you can pass the api key in Authorization header (ie. from 'Authorization: Basic xxx' header)\n* `Allow client id only usage`: you can pass the api key using client id only (ie. from Otoroshi-Token header)\n* `From custom headers`: you can pass the api key using custom headers (ie. Otoroshi-Client-Id and Otoroshi-Client-Secret headers)\n* `From JWT token`: you can pass the api key using a JWT token (ie. from 'Authorization: Bearer xxx' header)\n\n#### Basic auth. Api Key\n\n* `Custom header name`: the name of the header to get Authorization\n* `Custom query param name`: the name of the query param to get Authorization\n\n#### Client ID only Api Key\n\n* `Custom header name`: the name of the header to get the client id\n* `Custom query param name`: the name of the query param to get the client id\n\n#### Custom headers Api Key\n\n* `Custom client id header name`: the name of the header to get the client id\n* `Custom client secret header name`: the name of the header to get the client secret\n\n#### JWT Token Api Key\n\n* `Secret signed`: JWT can be signed by apikey secret using HMAC algo.\n* `Keypair signed`: JWT can be signed by an otoroshi managed keypair using RSA/EC algo.\n* `Include Http request attrs.`: if enabled, you have to put the following fields in the JWT token corresponding to the current http call (httpPath, httpVerb, httpHost)\n* `Max accepted token lifetime`: the maximum number of second accepted as token lifespan\n* `Custom header name`: the name of the header to get the jwt token\n* `Custom query param name`: the name of the query param to get the jwt token\n* `Custom cookie name`: the name of the cookie to get the jwt token\n\n### Routing constraints\n\n* `All Tags in` : have all of the following tags\n* `No Tags in` : not have one of the following tags\n* `One Tag in` : have at least one of the following tags\n* `All Meta. in` : have all of the following metadata entries\n* `No Meta. in` : not have one of the following metadata entries\n* `One Meta. in` : have at least one of the following metadata entries\n* `One Meta key in` : have at least one of the following key in metadata\n* `All Meta key in` : have all of the following keys in metadata\n* `No Meta key in` : not have one of the following keys in metadata\n\n### CORS support\n\n* `Enabled`: if enabled, CORS header will be check for each incoming request\n* `Allow credentials`: if enabled, the credentials will be sent. Credentials are cookies, authorization headers, or TLS client certificates.\n* `Allow origin`: if enabled, it will indicates whether the response can be shared with requesting code from the given\n* `Max age`: response header indicates how long the results of a preflight request (that is the information contained in the Access-Control-Allow-Methods and Access-Control-Allow-Headers headers) can be cached.\n* `Expose headers`: response header allows a server to indicate which response headers should be made available to scripts running in the browser, in response to a cross-origin request.\n* `Allow headers`: response header is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request.\n* `Allow methods`: response header specifies one or more methods allowed when accessing a resource in response to a preflight request.\n* `Excluded patterns`: by default, when cors is enabled, everything has cors. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n\n#### Related documentations\n\n* @link[Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials) { open=new }\n* @link[Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) { open=new }\n* @link[Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age) { open=new }\n* @link[Access-Control-Allow-Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods) { open=new }\n* @link[Access-Control-Allow-Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers) { open=new }\n\n### JWT tokens verification\n\n* `Verifiers`: list of selected verifiers to apply on the service\n* `Enabled`: if enabled, Otoroshi will enabled each verifier of the previous list\n* `Excluded patterns`: list of routes where the verifiers will not be apply\n\n### Pre Routing\n\nThis part has been deprecated and moved to the plugin section.\n\n### Access validation\nThis part has been deprecated and moved to the plugin section.\n\n### Gzip support\n\n* `Mimetypes allowed list`: gzip only the files that are matching to a format in the list\n* `Mimetypes blocklist`: will not gzip files matching to a format in the list. A possible way is to allowed all format by default by setting a `*` on the `Mimetypes allowed list` and to add the unwanted format in this list.\n* `Compression level`: the compression level where 9 gives us maximum compression but at the slowest speed. The default compression level is 5 and is a good compromise between speed and compression ratio.\n* `Buffer size`: chunking up a stream of bytes into limited size\n* `Chunk threshold`: if the content type of a request reached over the threshold, the response will be chunked\n* `Excluded patterns`: by default, when gzip is enabled, everything has gzip. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.\n\n### Client settings\n\n* `Use circuit breaker`: use a circuit breaker to avoid cascading failure when calling chains of services. Highly recommended !\n* `Cache connections`: use a cache at host connection level to avoid reconnection time\n* `Client attempts`: specify how many times the client will retry to fetch the result of the request after an error before giving up.\n* `Client call timeout`: specify how long each call should last at most in milliseconds.\n* `Client call and stream timeout`: specify how long each call should last at most in milliseconds for handling the request and streaming the response.\n* `Client connection timeout`: specify how long each connection should last at most in milliseconds.\n* `Client idle timeout`: specify how long each connection can stay in idle state at most in milliseconds.\n* `Client global timeout`: specify how long the global call (with retries) should last at most in milliseconds.\n* `C.breaker max errors`: specify how many errors can pass before opening the circuit breaker\n* `C.breaker retry delay`: specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor\n* `C.breaker backoff factor`: specify the factor to multiply the delay for each retry\n* `C.breaker window`: specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted\n\n#### Custom timeout settings (list)\n\n* `Path`: the path on which the timeout will be active\n* `Client connection timeout`: specify how long each connection should last at most in milliseconds.\n* `Client idle timeout`: specify how long each connection can stay in idle state at most in milliseconds.\n* `Client call and stream timeout`: specify how long each call should last at most in milliseconds for handling the request and streaming the response.\n* `Call timeout`: Specify how long each call should last at most in milliseconds.\n* `Client global timeout`: specify how long the global call (with retries) should last at most in milliseconds.\n\n#### Proxy settings\n\n* `Proxy host`: host of proxy behind the identify provider\n* `Proxy port`: port of proxy behind the identify provider\n* `Proxy principal`: user of proxy \n* `Proxy password`: password of proxy\n\n### HTTP Headers\n\n* `Additional Headers In`: specify headers that will be added to each client request (from Otoroshi to target). Useful to add authentication.\n* `Additional Headers Out`: specify headers that will be added to each client response (from Otoroshi to client).\n* `Missing only Headers In`: specify headers that will be added to each client request (from Otoroshi to target) if not in the original request.\n* `Missing only Headers Out`: specify headers that will be added to each client response (from Otoroshi to client) if not in the original response.\n* `Remove incoming headers`: remove headers in the client request (from client to Otoroshi).\n* `Remove outgoing headers`: remove headers in the client response (from Otoroshi to client).\n* `Security headers`:\n* `Utility headers`:\n* `Matching Headers`: specify headers that MUST be present on client request to route it (pre routing). Useful to implement versioning.\n* `Headers verification`: verify that some headers has a specific value (post routing)\n\n### Additional settings \n\n* `OpenAPI`: specify an open API descriptor. Useful to display the documentation\n* `Tags`: specify tags for the service\n* `Metadata`: specify metadata for the service. Useful for analytics\n* `IP allowed list`: IP address that can access the service\n* `IP blocklist`: IP address that cannot access the service\n\n### Canary mode\n\n* `Enabled`: Canary mode enabled\n* `Traffic split`: Ratio of traffic that will be sent to canary targets. For instance, if traffic is at 0.2, for 10 request, 2 request will go on canary targets and 8 will go on regular targets.\n* `Targets`: The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures\n * `Target`:\n * `Targets root`: Otoroshi will append this root to any target choosen. If the specified root is '/api/foo', then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar\n* `Campaign stats`:\n* `Use canary targets as standard targets`:\n\n### Healthcheck settings\n\n* `HealthCheck enabled`: to help failing fast, you can activate healthcheck on a specific URL.\n* `HealthCheck url`: the URL to check. Should return an HTTP 200 response. You can also respond with an 'Opun-Health-Check-Logic-Test-Result' header set to the value of the 'Opun-Health-Check-Logic-Test' request header + 42. to make the healthcheck complete.\n\n### Fault injection\n\n* `User facing app.`: if service is set as user facing, Snow Monkey can be configured to not being allowed to create outage on them.\n* `Chaos enabled`: activate or deactivate chaos setting on this service descriptor.\n\n### Custom errors template\n\n* `40x template`: html template displayed when 40x error occurred\n* `50x template`: html template displayed when 50x error occurred\n* `Build mode template`: html template displayed when the build mode is enabled\n* `Maintenance mode template`: html template displayed when the maintenance mode is enabled\n* `Custom messages`: override error message one by one\n\n### Request transformation\n\nThis part has been deprecated and moved to the plugin section.\n\n### Plugins\n\n* `Plugins`:\n \n * `Inject default config`: injects, if present, the default configuration of a selected plugin in the configuration object\n * `Documentation`: link to the documentation website of the plugin\n * `show/hide config. panel`: shows and hides the plugin panel which contains the plugin description and configuration\n* `Excluded patterns`: by default, when plugins are enabled, everything pass in. But sometimes you need to exclude something, so just add regex to matching path you want to exlude.\n* `Configuration`: the configuration of each enabled plugin, split by names and grouped in the same configuration object."},{"name":"service-groups.md","id":"/entities/service-groups.md","url":"/entities/service-groups.html","title":"Service groups","content":"# Service groups\n\nA service group is composed of an unique `id`, a `Group name`, a `Group description`, an `Organization` and a `Team`. As all Otoroshi resources, a service group have a list of tags and metadata associated.\n\n@@@ div { .centered-img }\n\n@@@\n\nThe first instinctive usage of service group is to group a list of services. \n\nWhen it's done, you can authorize an api key on a specific group. Instead of authorize an api key for each service, you can regroup a list of services together, and give authorization on the group (read the page on the api keys and the usage of the `Authorized on.` field).\n\n## Access to the list of service groups\n\nTo visualize and edit the list of groups, you can navigate to your instance on the `https://otoroshi.xxxxx/bo/dashboard/groups` route or click on the cog icon and select the Service groups button.\n\nOnce on the page, you can create a new item, edit an existing service group or delete an existing one.\n\n> When a service group is deleted, the resources associated are not deleted. On the other hand, the service group of associated resources is let empty.\n\n"},{"name":"tcp-services.md","id":"/entities/tcp-services.md","url":"/entities/tcp-services.html","title":"TCP services","content":"# TCP services\n\nTCP service are special kind of otoroshi services meant to proxy pure TCP connections (ssh, database, http, etc)\n\n## Global information\n\n* `Id`: generated unique identifier\n* `TCP service name`: the name of your TCP service\n* `Enabled`: enable and disable the service\n* `TCP service port`: the listening port\n* `TCP service interface`: network interface listen by the service\n* `Tags`: list of tags associated to the service\n* `Metadata`: list of metadata associated to the service\n\n## TLS\n\nthis section controls the TLS exposition of the service\n\n* `TLS mode`\n * `Disabled`: no TLS\n * `PassThrough`: as the target exposes TLS, the call will pass through otoroshi and use target TLS\n * `Enabled`: the service will be exposed using TLS and will chose certificate based on SNI\n* `Client Auth.`\n * `None` no mTLS needed to pass\n * `Want` pass with or without mTLS\n * `Need` need mTLS to pass\n\n## Server Name Indication (SNI)\n\nthis section control how SNI should be treated\n\n* `SNI routing enabled`: if enabled, the server will use the SNI hostname to determine which certificate to present to the client\n* `Forward to target if no SNI match`: if enabled, a call without any SNI match will be forward to the target\n* `Target host`: host of the target called if no SNI\n* `Target ip address`: ip of the target called if no SNI\n* `Target port`: port of the target called if no SNI\n* `TLS call`: encrypt the communication with TLS\n\n## Rules\n\nfor any listening TCP proxy, it is possible to route to multiple targets based on SNI or extracted http host (if proxying http)\n\n* `Matching domain name`: regex used to filter the list of domains where the rule will be applied\n* `Target host`: host of the target\n* `Target ip address`: ip of the target\n* `Target port`: port of the target\n* `TLS call`: enable this flag if the target is exposed using TLS\n"},{"name":"teams.md","id":"/entities/teams.md","url":"/entities/teams.html","title":"Teams","content":"# Teams\n\nIn Otoroshi, all resources are attached to an `Organization` and a `Team`. \n\nA team is composed of an unique `id`, a `name`, a `description` and an `Organization`. As all Otoroshi resources, a Team have a list of tags and metadata associated.\n\nA team have an unique organization and can be use on multiples resources (services, api keys, etc ...).\n\nA connected user on Otoroshi UI has a list of teams and organizations associated. It can be helpful when you want restrict the rights of a connected user.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Access to the list of teams\n\nTo visualize and edit the list of teams, you can navigate to your instance on the `https://otoroshi.xxxxxx/bo/dashboard/teams` route or click on the cog icon and select the teams button.\n\nOnce on the page, you can create a new item, edit an existing team or delete an existing one.\n\n> When a team is deleted, the resources associated are not deleted. On the other hand, the team of associated resources is let empty.\n\n## Entities location\n\nAny otoroshi entity has a location property (`_loc` when serialized to json) explaining where and by whom the entity can be seen. \n\nAn entity can be part of multiple teams in an organization\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": [\n \"team-1\",\n \"team-2\"\n ]\n }\n ...\n}\n```\n\nor all teams\n\n```javascript\n{\n \"_loc\": {\n \"tenant\": \"tenant-1\",\n \"teams\": [\n \"*\"\n ]\n }\n ...\n}\n```"},{"name":"features.md","id":"/features.md","url":"/features.html","title":"Features","content":"# Features\n\n**Traffic Management**\n\n* Can proxy any HTTP(s) service (apis, webapps, websocket, etc)\n* Can proxy any TCP service (app, database, etc)\n* Traffic mirroring\n* Canary deployments\n* Multiple load-balancing options: RoundRobin, Random, Sticky, Ip Hash, Best Response Time\n* Distributed in-flight request limiting\t\n* Distributed rate limiting \n\n**Services customization**\n\n* Dozens of built-in middlewares (plugins) \n * circuit breakers\n * automatic retries\n * buffering\n * gzip\n * headers manipulation\n * cors\n * etc \n* Custom middleware\n* Higly customizable visibility\n\n**Services Monitoring**\n\n* Active health checks\n* Calls tracing\n* Export alerts and events to external database\n* Real-time traffic metrics\n* Alert mailers\n* Real-time traffic metrics (Datadog, Prometheus, StatsD)\n\n**API security**\n\n* Access management with apikeys and quotas\n* Automatic apikeys secrets rotation\n* HTTPS and TLS\n* mTLS in/out calls \n* Routing constraints\n* Routing restrictions\n* JWT tokens validation and manipulation\n\n**Administration UI**\n\n* Manage and organize all resources\n* Secured users access with Authentication module\n* Traced users actions\n* Dynamic changes at runtime without full reload\n\n**Webapp authentication and security**\n\n* OAuth2.0/2.1 authentication\n* OpenID Connect (OIDC) authentication\n* Internal users management\n* LDAP authentication\n* JWT authentication\n* OAuth 1.0a authentication\n* SAML V2 authentication\n\n**Certificates management**\n\n* Dynamic TLS certificates store \n* Dynamic TLS termination\n* Internal PKI\n* ACME / Let's Encrypt support\n* On-the-fly certificate generation based on a CA certificate without request loss\n\n**Performances and testing**\n\n* Chaos engineering\n* Clustering with encrypted communication\n* Scalability\n\n**Kubernetes integration**\n\n* Standard Ingress controller\n* Custom Ingress controller\n * Manage Otoroshi resources from Kubernetes\n* Validation of resources via webhook\n* Service Mesh for easy service-to-service communication\n\n**Developpers portal**\n\n* Using @link:[Daikoku](https://maif.github.io/daikoku/manual/index.html) { open=new }\n"},{"name":"getting-started.md","id":"/getting-started.md","url":"/getting-started.html","title":"Getting Started","content":"# Getting Started\n\n- [Protect the access to your api with the Otoroshi management of api keys](#protect-the-access-to-your-api-with-the-otoroshi-management-of-api-keys)\n- [Secure your web app in 5 minutes with an authentication](#secure-your-web-app-in-5-minutes-with-an-authentication)\n\nDownload the latest jar of Otoroshi\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nOnce downloading, run Otoroshi.\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\n## Protect the access to your api with the Otoroshi management of api keys\n\nCreate a service, exposed on `http://myapi.oto.tools:8080`, which will forward all requests to the mirror `https://mirror.otoroshi.io`.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n-d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"myapi\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"myapi\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\"],\"privatePatterns\":[\"\\/.*\"],\"kind\":\"ServiceDescriptor\"}' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nTry to call this service. You should receive an error from Otoroshi about a missing api key in our request.\n\n```sh\ncurl 'http://myapi.oto.tools:8080'\n```\n\nCreate your first api key with a quota of 10 calls by day and month.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/apikeys' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret \\\n-d @- <<'EOF'\n{\n \"clientId\": \"my-first-apikey-id\",\n \"clientSecret\": \"my-first-apikey-secret\",\n \"clientName\": \"my-first-apikey\",\n \"description\": \"my-first-apikey-description\",\n \"authorizedGroup\": \"default\",\n \"enabled\": true,\n \"throttlingQuota\": 10,\n \"dailyQuota\": 10,\n \"monthlyQuota\": 10\n}\nEOF\n```\n\nCall your api with the generated apikey.\n\n```sh\ncurl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret\n```\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.otoroshi.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"authorization\": \"Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==\",\n \"otoroshi-request-id\": \"1465298507974836306\",\n \"otoroshi-proxied-host\": \"myapi.oto.tools:8080\",\n \"otoroshi-request-timestamp\": \"2021-11-29T13:36:02.888+01:00\",\n },\n \"body\": \"\"\n}\n```\n\nCheck your remaining quotas\n\n```sh\ncurl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret --include\n```\n\nThis should output these following Otoroshi headers\n\n```json\nOtoroshi-Daily-Calls-Remaining: 6\nOtoroshi-Monthly-Calls-Remaining: 6\n```\n\nKeep calling the api and confirm that Otoroshi is sending you an apikey exceeding quota error\n\n\n```json\n{ \n \"Otoroshi-Error\": \"You performed too much requests\"\n}\n```\n\nWell done, you have secured your first api with the apikeys system with limited call quotas.\n\n## Secure your web app in 5 minutes with an authentication\n\nCreate an in-memory authentication module, with one registered user, to protect your service.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/auths' \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\n \"type\":\"basic\",\n \"id\":\"auth_mod_in_memory_auth\",\n \"name\":\"in-memory-auth\",\n \"desc\":\"in-memory-auth\",\n \"users\":[\n {\n \"name\":\"User Otoroshi\",\n \"password\":\"$2a$10$oIf4JkaOsfiypk5ZK8DKOumiNbb2xHMZUkYkuJyuIqMDYnR/zXj9i\",\n \"email\":\"user@foo.bar\",\n \"metadata\":{\n \"username\":\"roger\"\n },\n \"tags\":[\"foo\"],\n \"webauthn\":null,\n \"rights\":[{\n \"tenant\":\"*:r\",\n \"teams\":[\"*:r\"]\n }]\n }\n ],\n \"sessionCookieValues\":{\n \"httpOnly\":true,\n \"secure\":false\n }\n}\nEOF\n```\n\nThen create a service secure by the previous authentication module, which proxies `google.fr` on `webapp.oto.tools`.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n-d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"webapp\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"webapp\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"google.fr\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\\/.*\"],\"privatePatterns\":[\"\"],\"kind\":\"ServiceDescriptor\",\"authConfigRef\":\"auth_mod_in_memory_auth\",\"privateApp\":true}' \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nNavigate to http://webapp.oto.tools:8080, login with `user@foo.bar/password` and check that you're redirect to `google` page.\n\nWell done! You completed the discovery tutorial."},{"name":"custom-initial-state.md","id":"/how-to-s/custom-initial-state.md","url":"/how-to-s/custom-initial-state.html","title":"Initial state customization","content":"# Initial state customization\n\nwhen you start otoroshi for the first time, some basic entities will be created and stored in the datastore in order to make your instance work properly. However it might not be enough for your use case but you do want to bother with restoring a complete otoroshi export.\n\nIn order to make state customization easy, otoroshi provides the config. key `otoroshi.initialCustomization`, overriden by the env. variable `OTOROSHI_INITIAL_CUSTOMIZATION`\n\nThe expected structure is the following :\n\n```javascript\n{\n \"config\": { ... },\n \"admins\": [],\n \"simpleAdmins\": [],\n \"serviceGroups\": [],\n \"apiKeys\": [],\n \"serviceDescriptors\": [],\n \"errorTemplates\": [],\n \"jwtVerifiers\": [],\n \"authConfigs\": [],\n \"certificates\": [],\n \"clientValidators\": [],\n \"scripts\": [],\n \"tcpServices\": [],\n \"dataExporters\": [],\n \"tenants\": [],\n \"teams\": []\n}\n```\n\nin this structure, everything is optional. For every array property, items will be added to the datastore. For the global config. object, you can just add the parts that you need, and they will be merged with the existing config. object of the datastore.\n\n## Customize the global config.\n\nfor instance, if you want to customize the behavior of the TLS termination, you can use the following :\n\n```sh\nexport OTOROSHI_INITIAL_CUSTOMIZATION='{\"config\":{\"tlsSettings\":{\"defaultDomain\":\"www.foo.bar\",\"randomIfNotFound\":false}}'\n```\n\n## Customize entities\n\nif you want to add apikeys at first boot \n\n```sh\nexport OTOROSHI_INITIAL_CUSTOMIZATION='{\"apikeys\":[{\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"clientId\":\"ksVlQ2KlZm0CnDfP\",\"clientSecret\":\"usZYbE1iwSsbpKY45W8kdbZySj1M5CWvFXe0sPbZ0glw6JalMsgorDvSBdr2ZVBk\",\"clientName\":\"awesome-apikey\",\"description\":\"the awesome apikey\",\"authorizedGroup\":\"default\",\"authorizedEntities\":[\"group_default\"],\"enabled\":true,\"readOnly\":false,\"allowClientIdOnly\":false,\"throttlingQuota\":10000000,\"dailyQuota\":10000000,\"monthlyQuota\":10000000,\"constrainedServicesOnly\":false,\"restrictions\":{\"enabled\":false,\"allowLast\":true,\"allowed\":[],\"forbidden\":[],\"notFound\":[]},\"rotation\":{\"enabled\":false,\"rotationEvery\":744,\"gracePeriod\":168,\"nextSecret\":null},\"validUntil\":null,\"tags\":[],\"metadata\":{}}]}'\n```\n"},{"name":"custom-log-levels.md","id":"/how-to-s/custom-log-levels.md","url":"/how-to-s/custom-log-levels.html","title":"Log levels customization","content":"# Log levels customization\n\nIf you want to customize the log level of your otoroshi instances, it's pretty easy to do it using environment variables or configuration file.\n\n## Customize log level for one logger with configuration file\n\nLet say you want to see `DEBUG` messages from the logger `otoroshi-http-handler`.\n\nThen you just have to declare in your otoroshi configuration file\n\n```\notoroshi.loggers {\n ...\n otoroshi-http-handler = \"DEBUG\"\n ...\n}\n```\n\npossible levels are `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`. Default one is `WARN`.\n\n## Customize log level for one logger with environment variable\n\nLet say you want to see `DEBUG` messages from the logger `otoroshi-http-handler`.\n\nThen you just have to declare an environment variable named `OTOROSHI_LOGGERS_OTOROSHI_HTTP_HANDLER` with value `DEBUG`. The rule is \n\n```scala\n\"OTOROSHI_LOGGERS_\" + loggerName.toUpperCase().replace(\"-\", \"_\")\n```\n\npossible levels are `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`. Default one is `WARN`.\n\n## List of loggers\n\n* [`otoroshi-error-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-error-handler%22%29)\n* [`otoroshi-http-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler%22%29)\n* [`otoroshi-http-handler-debug`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler-debug%22%29)\n* [`otoroshi-websocket-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket-handler%22%29)\n* [`otoroshi-websocket`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket%22%29)\n* [`otoroshi-websocket-handler-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-websocket-handler-actor%22%29)\n* [`otoroshi-snowmonkey`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snowmonkey%22%29)\n* [`otoroshi-circuit-breaker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-circuit-breaker%22%29)\n* [`otoroshi-circuit-breaker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-circuit-breaker%22%29)\n* [`otoroshi-worker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-worker%22%29)\n* [`otoroshi-http-handler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-handler%22%29)\n* [`otoroshi-auth-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-controller%22%29)\n* [`otoroshi-swagger-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-swagger-controller%22%29)\n* [`otoroshi-u2f-controller`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-u2f-controller%22%29)\n* [`otoroshi-backoffice-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-backoffice-api%22%29)\n* [`otoroshi-health-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-health-api%22%29)\n* [`otoroshi-stats-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-stats-api%22%29)\n* [`otoroshi-admin-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-admin-api%22%29)\n* [`otoroshi-auth-modules-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-modules-api%22%29)\n* [`otoroshi-certificates-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificates-api%22%29)\n* [`otoroshi-pki`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-pki%22%29)\n* [`otoroshi-scripts-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-scripts-api%22%29)\n* [`otoroshi-analytics-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-api%22%29)\n* [`otoroshi-import-export-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-import-export-api%22%29)\n* [`otoroshi-templates-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-templates-api%22%29)\n* [`otoroshi-teams-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-teams-api%22%29)\n* [`otoroshi-events-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-events-api%22%29)\n* [`otoroshi-canary-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-canary-api%22%29)\n* [`otoroshi-data-exporter-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-api%22%29)\n* [`otoroshi-services-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-services-api%22%29)\n* [`otoroshi-tcp-service-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-service-api%22%29)\n* [`otoroshi-tenants-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tenants-api%22%29)\n* [`otoroshi-global-config-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-config-api%22%29)\n* [`otoroshi-apikeys-fs-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-fs-api%22%29)\n* [`otoroshi-apikeys-fg-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-fg-api%22%29)\n* [`otoroshi-apikeys-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-api%22%29)\n* [`otoroshi-statsd-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-statsd-actor%22%29)\n* [`otoroshi-snow-monkey-api`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snow-monkey-api%22%29)\n* [`otoroshi-jobs-eventstore-checker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jobs-eventstore-checker%22%29)\n* [`otoroshi-initials-certs-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-initials-certs-job%22%29)\n* [`otoroshi-alert-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alert-actor%22%29)\n* [`otoroshi-alert-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alert-actor-supervizer%22%29)\n* [`otoroshi-alerts`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-alerts%22%29)\n* [`otoroshi-apikeys-secrets-rotation-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-secrets-rotation-job%22%29)\n* [`otoroshi-loader`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-loader%22%29)\n* [`otoroshi-api-action`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-api-action%22%29)\n* [`otoroshi-api-action`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-api-action%22%29)\n* [`otoroshi-analytics-writes-elastic`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-writes-elastic%22%29)\n* [`otoroshi-analytics-reads-elastic`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-reads-elastic%22%29)\n* [`otoroshi-events-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-events-actor-supervizer%22%29)\n* [`otoroshi-data-exporter`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter%22%29)\n* [`otoroshi-data-exporter-update-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-update-job%22%29)\n* [`otoroshi-kafka-wrapper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-kafka-wrapper%22%29)\n* [`otoroshi-kafka-connector`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-kafka-connector%22%29)\n* [`otoroshi-analytics-webhook`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-webhook%22%29)\n* [`otoroshi-jobs-software-updates`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jobs-software-updates%22%29)\n* [`otoroshi-analytics-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-actor%22%29)\n* [`otoroshi-analytics-actor-supervizer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-actor-supervizer%22%29)\n* [`otoroshi-analytics-event`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-analytics-event%22%29)\n* [`otoroshi-env`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-env%22%29)\n* [`otoroshi-script-compiler`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script-compiler%22%29)\n* [`otoroshi-script-manager`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script-manager%22%29)\n* [`otoroshi-script`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-script%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-tcp-proxy`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-tcp-proxy%22%29)\n* [`otoroshi-custom-timeouts`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-custom-timeouts%22%29)\n* [`otoroshi-client-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-client-config%22%29)\n* [`otoroshi-canary`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-canary%22%29)\n* [`otoroshi-redirection-settings`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redirection-settings%22%29)\n* [`otoroshi-service-descriptor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-descriptor%22%29)\n* [`otoroshi-service-descriptor-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-descriptor-datastore%22%29)\n* [`otoroshi-console-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-console-mailer%22%29)\n* [`otoroshi-mailgun-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mailgun-mailer%22%29)\n* [`otoroshi-mailjet-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mailjet-mailer%22%29)\n* [`otoroshi-sendgrid-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-sendgrid-mailer%22%29)\n* [`otoroshi-generic-mailer`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-generic-mailer%22%29)\n* [`otoroshi-clevercloud-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-clevercloud-client%22%29)\n* [`otoroshi-metrics`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-metrics%22%29)\n* [`otoroshi-gzip-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-gzip-config%22%29)\n* [`otoroshi-regex-pool`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-regex-pool%22%29)\n* [`otoroshi-ws-client-chooser`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ws-client-chooser%22%29)\n* [`otoroshi-akka-ws-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-akka-ws-client%22%29)\n* [`otoroshi-http-implicits`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-implicits%22%29)\n* [`otoroshi-service-group`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-group%22%29)\n* [`otoroshi-data-exporter-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-config%22%29)\n* [`otoroshi-data-exporter-config-migration-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-data-exporter-config-migration-job%22%29)\n* [`otoroshi-lets-encrypt-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lets-encrypt-helper%22%29)\n* [`otoroshi-apkikey`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apkikey%22%29)\n* [`otoroshi-error-template`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-error-template%22%29)\n* [`otoroshi-job-manager`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-job-manager%22%29)\n* [`otoroshi-plugins-internal-eventlistener-actor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-internal-eventlistener-actor%22%29)\n* [`otoroshi-global-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-config%22%29)\n* [`otoroshi-jwks`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jwks%22%29)\n* [`otoroshi-jwt-verifier`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-jwt-verifier%22%29)\n* [`otoroshi-global-jwt-verifier`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-jwt-verifier%22%29)\n* [`otoroshi-snowmonkey-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-snowmonkey-config%22%29)\n* [`otoroshi-webauthn-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-webauthn-admin-datastore%22%29)\n* [`otoroshi-webauthn-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-webauthn-admin-datastore%22%29)\n* [`otoroshi-leveldb-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-leveldb-datastores%22%29)\n* [`otoroshi-service-datatstore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-service-datatstore%22%29)\n* [`otoroshi-cassandra-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cassandra-datastores%22%29)\n* [`otoroshi-redis-like-store`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redis-like-store%22%29)\n* [`otoroshi-globalconfig-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-globalconfig-datastore%22%29)\n* [`otoroshi-mongo-redis`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mongo-redis%22%29)\n* [`otoroshi-mongo-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-mongo-datastores%22%29)\n* [`otoroshi-reactive-pg-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-reactive-pg-datastores%22%29)\n* [`otoroshi-reactive-pg-kv`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-reactive-pg-kv%22%29)\n* [`otoroshi-cassandra-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cassandra-datastores%22%29)\n* [`otoroshi-apikey-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikey-datastore%22%29)\n* [`otoroshi-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-datastore%22%29)\n* [`otoroshi-certificate-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificate-datastore%22%29)\n* [`otoroshi-simple-admin-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-simple-admin-datastore%22%29)\n* [`otoroshi-atomic-in-memory-datastore`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-atomic-in-memory-datastore%22%29)\n* [`otoroshi-lettuce-redis`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lettuce-redis%22%29)\n* [`otoroshi-lettuce-redis-cluster`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-lettuce-redis-cluster%22%29)\n* [`otoroshi-redis-lettuce-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-redis-lettuce-datastores%22%29)\n* [`otoroshi-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-datastores%22%29)\n* [`otoroshi-file-db-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-file-db-datastores%22%29)\n* [`otoroshi-http-db-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-http-db-datastores%22%29)\n* [`otoroshi-s3-datastores`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-s3-datastores%22%29)\n* [`PluginDocumentationGenerator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22PluginDocumentationGenerator%22%29)\n* [`otoroshi-health-checker`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-health-checker%22%29)\n* [`otoroshi-healthcheck-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-healthcheck-job%22%29)\n* [`otoroshi-healthcheck-local-cache-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-healthcheck-local-cache-job%22%29)\n* [`otoroshi-plugins-response-cache`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-response-cache%22%29)\n* [`otoroshi-oidc-apikey-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-oidc-apikey-config%22%29)\n* [`otoroshi-plugins-maxmind-geolocation-info`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-maxmind-geolocation-info%22%29)\n* [`otoroshi-plugins-ipstack-geolocation-info`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-ipstack-geolocation-info%22%29)\n* [`otoroshi-plugins-maxmind-geolocation-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-maxmind-geolocation-helper%22%29)\n* [`otoroshi-plugins-user-agent-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-user-agent-helper%22%29)\n* [`otoroshi-plugins-user-agent-extractor`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-user-agent-extractor%22%29)\n* [`otoroshi-global-el`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-el%22%29)\n* [`otoroshi-plugins-oauth1-caller-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-oauth1-caller-plugin%22%29)\n* [`otoroshi-dynamic-sslcontext`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-dynamic-sslcontext%22%29)\n* [`otoroshi-plugins-access-log-clf`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-access-log-clf%22%29)\n* [`otoroshi-plugins-access-log-json`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-access-log-json%22%29)\n* [`otoroshi-plugins-kafka-access-log`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kafka-access-log%22%29)\n* [`otoroshi-plugins-kubernetes-client`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-client%22%29)\n* [`otoroshi-plugins-kubernetes-ingress-controller-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-ingress-controller-job%22%29)\n* [`otoroshi-plugins-kubernetes-ingress-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-ingress-sync%22%29)\n* [`otoroshi-plugins-kubernetes-crds-controller-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-crds-controller-job%22%29)\n* [`otoroshi-plugins-kubernetes-crds-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-crds-sync%22%29)\n* [`otoroshi-cluster`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cluster%22%29)\n* [`otoroshi-crd-validator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-crd-validator%22%29)\n* [`otoroshi-sidecar-injector`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-sidecar-injector%22%29)\n* [`otoroshi-plugins-kubernetes-cert-sync`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-cert-sync%22%29)\n* [`otoroshi-plugins-kubernetes-to-otoroshi-certs-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-kubernetes-to-otoroshi-certs-job%22%29)\n* [`otoroshi-plugins-otoroshi-certs-to-kubernetes-secrets-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-otoroshi-certs-to-kubernetes-secrets-job%22%29)\n* [`otoroshi-apikeys-workflow-job`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-apikeys-workflow-job%22%29)\n* [`otoroshi-cert-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert-helper%22%29)\n* [`otoroshi-certificates-ocsp`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-certificates-ocsp%22%29)\n* [`otoroshi-claim`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-claim%22%29)\n* [`otoroshi-cert`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert%22%29)\n* [`otoroshi-ssl-provider`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ssl-provider%22%29)\n* [`otoroshi-cert-data`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-cert-data%22%29)\n* [`otoroshi-client-cert-validator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-client-cert-validator%22%29)\n* [`otoroshi-ssl-implicits`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ssl-implicits%22%29)\n* [`otoroshi-saml-validator-utils`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-saml-validator-utils%22%29)\n* [`otoroshi-global-saml-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-saml-config%22%29)\n* [`otoroshi-plugins-hmac-caller-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hmac-caller-plugin%22%29)\n* [`otoroshi-plugins-hmac-access-validator-plugin`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hmac-access-validator-plugin%22%29)\n* [`otoroshi-plugins-hasallowedusersvalidator`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-hasallowedusersvalidator%22%29)\n* [`otoroshi-auth-module-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-auth-module-config%22%29)\n* [`otoroshi-basic-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-basic-auth-config%22%29)\n* [`otoroshi-ldap-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ldap-auth-config%22%29)\n* [`otoroshi-plugins-jsonpath-helper`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-plugins-jsonpath-helper%22%29)\n* [`otoroshi-global-oauth2-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-oauth2-config%22%29)\n* [`otoroshi-global-oauth2-module`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-global-oauth2-module%22%29)\n* [`otoroshi-ldap-auth-config`](https://github.com/MAIF/otoroshi/search?q=Logger%28%22otoroshi-ldap-auth-config%22%29)\n"},{"name":"end-to-end-mtls.md","id":"/how-to-s/end-to-end-mtls.md","url":"/how-to-s/end-to-end-mtls.html","title":"End-to-end mTLS","content":"# End-to-end mTLS\n\nIf you want to use MTLS on otoroshi, you first need to enable it. It is not enabled by default as it will make TLS handshake way heavier. \nTo enable it just change the following config :\n\n```sh\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```sh\nSSL_OUTSIDE_CLIENT_AUTH=None|Want|Need\n```\n\nYou can use the `Want` setup if you cant to have both mtls on some services and no mtls on other services.\n\nYou can also change the trusted CA list sent in the handshake certificate request from the `Danger Zone` in `Tls Settings`.\n\nOtoroshi support mutual TLS out of the box. mTLS from client to Otoroshi and from Otoroshi to targets are supported. In this article we will see how to configure Otoroshi to use end-to-end mTLS. All code and files used in this articles can be found on the [Otoroshi github](https://github.com/MAIF/otoroshi/tree/master/demos/mtls)\n\n### Create certificates\n\nBut first we need to generate some certificates to make the demo work\n\n```sh\nmkdir mtls-demo\ncd mtls-demo\nmkdir ca\nmkdir server\nmkdir client\n\n# create a certificate authority key, use password as pass phrase\nopenssl genrsa -out ./ca/ca-backend.key 4096\n# remove pass phrase\nopenssl rsa -in ./ca/ca-backend.key -out ./ca/ca-backend.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key ./ca/ca-backend.key -out ./ca/ca-backend.cer -subj \"/CN=MTLSB\"\n\n\n# create a certificate authority key, use password as pass phrase\nopenssl genrsa -out ./ca/ca-frontend.key 2048\n# remove pass phrase\nopenssl rsa -in ./ca/ca-frontend.key -out ./ca/ca-frontend.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key ./ca/ca-frontend.key -out ./ca/ca-frontend.cer -subj \"/CN=MTLSF\"\n\n\n# now create the backend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.backend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.backend.oto.tools.key -out ./server/_.backend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.backend.oto.tools.key -sha256 -out ./server/_.backend.oto.tools.csr -subj \"/CN=*.backend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.oto.tools.cer\n# verify the certificate, should output './server/_.backend.oto.tools.cer: OK'\nopenssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.oto.tools.cer\n\n\n# now create the frontend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.frontend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.frontend.oto.tools.key -out ./server/_.frontend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.frontend.oto.tools.key -sha256 -out ./server/_.frontend.oto.tools.csr -subj \"/CN=*.frontend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.oto.tools.cer\n# verify the certificate, should output './server/_.frontend.oto.tools.cer: OK'\nopenssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.cer\n\n\n# now create the client cert key for backend, use password as pass phrase\nopenssl genrsa -out ./client/_.backend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.csr -subj \"/CN=*.backend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.oto.tools.cer\n# generate a pem version of the cert and key, use password as password\nopenssl x509 -in client/_.backend.oto.tools.cer -out client/_.backend.oto.tools.pem -outform PEM\n\n\n# now create the client cert key for frontend, use password as pass phrase\nopenssl genrsa -out ./client/_.frontend.oto.tools.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.csr -subj \"/CN=*.frontend.oto.tools\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.oto.tools.cer\n# generate a pkcs12 version of the cert and key, use password as password\n# openssl pkcs12 -export -clcerts -in client/_.frontend.oto.tools.cer -inkey client/_.frontend.oto.tools.key -out client/_.frontend.oto.tools.p12\nopenssl x509 -in client/_.frontend.oto.tools.cer -out client/_.frontend.oto.tools.pem -outform PEM\n```\n\nOnce it's done, you should have something like\n\n```sh\n$ tree\n.\n├── backend.js\n├── ca\n│   ├── ca-backend.cer\n│   ├── ca-backend.key\n│   ├── ca-frontend.cer\n│   └── ca-frontend.key\n├── client\n│   ├── _.backend.oto.tools.cer\n│   ├── _.backend.oto.tools.csr\n│   ├── _.backend.oto.tools.key\n│   ├── _.backend.oto.tools.pem\n│   ├── _.frontend.oto.tools.cer\n│   ├── _.frontend.oto.tools.csr\n│   ├── _.frontend.oto.tools.key\n│   └── _.frontend.oto.tools.pem\n└── server\n ├── _.backend.oto.tools.cer\n ├── _.backend.oto.tools.csr\n ├── _.backend.oto.tools.key\n ├── _.frontend.oto.tools.cer\n ├── _.frontend.oto.tools.csr\n └── _.frontend.oto.tools.key\n\n3 directories, 18 files\n```\n\n### The backend service \n\nnow, let's create a backend service using nodejs. Create a file named `backend.js`\n\n```sh\ntouch backend.js\n```\n\nand put the following content\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nconst options = { \n key: fs.readFileSync('./server/_.backend.oto.tools.key'), \n cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n}; \n\nconst server = https.createServer(options, (req, res) => { \n res.writeHead(200, {\n 'Content-Type': 'application/json'\n }); \n res.end(JSON.stringify({ message: 'Hello World!' }) + \"\\n\"); \n}).listen(8444);\n\nconsole.log('Server listening:', `http://localhost:${server.address().port}`);\n```\n\nto run the server, just do \n\n```sh\nnode ./backend.js\n```\n\nnow you can try your server with\n\n```sh\ncurl --cacert ./ca/ca-backend.cer 'https://api.backend.oto.tools:8444/'\n```\n\nThis should output :\n```json\n{ \"message\": \"Hello World!\" }\n```\n\nnow modify your backend server to ensure that the client provides a client certificate like:\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nconst options = { \n key: fs.readFileSync('./server/_.backend.oto.tools.key'), \n cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nconst server = https.createServer(options, (req, res) => { \n console.log('Client certificate CN: ', req.socket.getPeerCertificate().subject.CN);\n res.writeHead(200, {\n 'Content-Type': 'application/json'\n }); \n res.end(JSON.stringify({ message: 'Hello World!' }) + \"\\n\"); \n}).listen(8444);\n\nconsole.log('Server listening:', `http://localhost:${server.address().port}`);\n```\n\nyou can test your new server with\n\n```sh\ncurl \\\n --cacert ./ca/ca-backend.cer \\\n --cert ./client/_.backend.oto.tools.pem \\\n --key ./client/_.backend.oto.tools.key 'https://api.backend.oto.tools:8444/'\n```\n\nthe output should be :\n\n```json\n{ \"message\": \"Hello World!\" }\n```\n\n### Otoroshi setup\n\nDownload the latest version of the Otoroshi jar and run it like\n\n```sh\n java \\\n -Dotoroshi.adminPassword=password \\\n -Dotoroshi.ssl.fromOutside.clientAuth=Want \\\n -jar -Dotoroshi.storage=file otoroshi.jar\n\n[info] otoroshi-env - Admin API exposed on http://otoroshi-api.oto.tools:8080\n[info] otoroshi-env - Admin UI exposed on http://otoroshi.oto.tools:8080\n[info] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[info] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[info] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / password\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n[info] p.c.s.AkkaHttpServer - Listening for HTTPS on /0:0:0:0:0:0:0:0:8443\n[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...\n```\n\nand log into otoroshi with the tuple `admin@otoroshi.io / password` displayed in the logs. \n\nOnce logged in, navigate to the services pages and create a new item.\n\n* Jump to the `Service exposition settings` and add `http://api.frontend.oto.tools` as `Exposed domain`. \n* Navigate to the `Service targets` and add the following url `https://api.backend.oto.tools:8444/` to redirect our call to the previous created backend. \n* End this step by exposing the service as `Public UI` on the `URL Patterns` section.\n\nand test it\n\n```sh\ncurl 'http://api.frontend.oto.tools:8080/'\n```\n\nThis should output :\n```json\n{\"Otoroshi-Error\": \"Something went wrong, you should try later. Thanks for your understanding.\"}\n```\n\nyou should get an error due to the fact that Otoroshi doesn't know about the server certificate or the client certificate expected by the server.\n\nWe have to add the client certificate for `https://api.backend.oto.tools` to Otoroshi. \n\nGo to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of `./client/_.backend.oto.tools.cer` and `./client/_.backend.oto.tools.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nIf you don't want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.\n\n```sh\ncat ./server/_.backend.oto.tools.cer ./ca/ca-backend.cer ./server/_.backend.oto.tools.key | curl \\\n -H 'Content-Type: text/plain' -X POST \\\n --data-binary @- \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n http://otoroshi-api.oto.tools:8080/api/certificates/_bundle \n```\n\nand retry the following curl command \n\n```sh\ncurl 'http://api.frontend.oto.tools:8080/'\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\nnow we have to expose `https://api.frontend.oto.tools:8443` using otoroshi. \n\nGo to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of `./server/_.frontend.oto.tools.cer` and `./server/_.frontend.oto.tools.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nIf you don't want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.\n\n```sh\ncat ./server/_.frontend.oto.tools.cer ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.key | curl \\\n -H 'Content-Type: text/plain' -X POST \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n --data-binary @- \\\n http://otoroshi-api.oto.tools:8080/api/certificates/_bundle\n```\n\nand try the following command\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\nnow we have to enforce the fact that we want client certificate for `api.frontend.oto.tools`. To do that, we have to add a `Client Validator Only` plugin on the `api.frontend.oto.tools` service. Scroll to the last section called `Plugins` and select the `Client validator only` in the list.\n\nnow if you retry \n\n```sh\ncurl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'\n```\nthe output should be\n\n```json\n{\"Otoroshi-Error\":\"bad request\"}\n```\n\nyou should get an error because no client cert. is passed with the request. But if you pass the `./client/_.frontend.oto.tools.csr` client cert and the key in your curl call\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\n### Client certificate matching plugin\n\nOtoroshi can restrict and check all incoming client certificates on a service.\n\nScroll to the `Plugins` section and select the `Client certificate matching` plugin. Then, click on the `show config. panel` and inject the default configuration of the plugin (by clicking on `Inject default config.`).\n\nSave the service and retry your call again.\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"Otoroshi-Error\":\"bad request\"}\n```\n\nOur client certificate is not matched by Otoroshi. We have to add the subject DN in the configuration of the `Client certificate matching` plugin to authorize it.\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"serialNumbers\": [],\n \"subjectDNs\": [\n \"CN=*.frontend.oto.tools\"\n ],\n \"issuerDNs\": [],\n \"regexSubjectDNs\": [],\n \"regexIssuerDNs\": []\n }\n}\n```\n\nSave the service and retry your call again.\n\n```sh\ncurl 'https://api.frontend.oto.tools:8443' \\\n --cacert ./ca/ca-frontend.cer \\\n --cert ./client/_.frontend.oto.tools.pem \\\n --key ./client/_.frontend.oto.tools.key\n```\nthe output should be\n\n```json\n{\"message\":\"Hello World!\"}\n```\n\n\n"},{"name":"export-alerts-using-mailgun.md","id":"/how-to-s/export-alerts-using-mailgun.md","url":"/how-to-s/export-alerts-using-mailgun.html","title":"Send alerts using mailgun","content":"# Send alerts using mailgun\n\nAll Otoroshi alerts can be send on different channels.\nOne of the ways is to send a group of specific alerts via emails.\n\nTo enable this behaviour, let's start by create an exporter of events.\n\nIn this tutorial, we will admit that you already have a mailgun account with an API key and a domain.\n\n## Create an Mailgun exporter\n\nLet's create an exporter. The exporter will export by default all events generated by Otoroshi.\n\n1. Go ahead, and navigate to http://otoroshi.oto.tools:8080\n2. Click on the cog icon on the top right\n3. Then `Exporters` button\n4. And add a new configuration when clicking on the `Add item` button\n5. Select the `mailer` in the `type` selector field\n6. Jump to `Exporter config` and select the `Mailgun` option\n7. Set the following values:\n* `EU` : false/true depending on your mailgun configuratin\n* `Mailgun api key` : your-mailgun-api-key\n* `Mailgun domain` : your-mailgun-domain\n* `Email addresses` : list of the recipient adresses\n\nWith this configuration, all Otoroshi events will be send to your listed addresses (we don't recommended to do that).\n\nTo filter events on `Alerts` type, we need to add the following configuration inside the `Filtering and projection` section (if you want to deep learn about this section, read this @ref:[part](../entities/data-exporters.md#matching-and-projections)).\n\n```json\n{\n \"include\": [\n { \"@type\": \"AlertEvent\" }\n ],\n \"exclude\": []\n}\n``` \n\nSave at the bottom page and enable the exporter (on the top of the page or in list of exporters). We will need to wait few seconds to receive the first alerts.\n\nThe **projection** field can be useful in the case you want to filter the fields contained in each alert sent.\n\nThe `Projection` field is a json where you can list the fields to keep for each alert.\n\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nWith this example, only `@type`, `@timestamp` and `@id` will be sent to the addresses of your recipients."},{"name":"export-events-to-elastic.md","id":"/how-to-s/export-events-to-elastic.md","url":"/how-to-s/export-events-to-elastic.html","title":"Export events to Elasticsearch","content":"# Export events to Elasticsearch\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Deploy a Elasticsearch and kibana stack on Docker\n\nLet's start by creating an Elasticsearch and Kibana stack on our machine (if it's already done for you, you can skip this section).\n\nTo start an Elasticsearch container for development or testing, run:\n\n```sh\ndocker network create elastic\ndocker pull docker.elastic.co/elasticsearch/elasticsearch:7.15.1\ndocker run --name es01-test --net elastic -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co/elasticsearch/elasticsearch:7.15.1\n```\n\n```sh\ndocker pull docker.elastic.co/kibana/kibana:7.15.1\ndocker run --name kib01-test --net elastic -p 5601:5601 -e \"ELASTICSEARCH_HOSTS=http://es01-test:9200\" docker.elastic.co/kibana/kibana:7.15.1\n```\n\nTo access Kibana, go to @link:[http://localhost:5601](http://localhost:5601) { open=new }.\n\n### Create an Elasticsearch exporter\n\nLet's create an exporter. The exporter will export by default all events generated by Otoroshi.\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n2. Click on the cog icon on the top right\n3. Then `Exporters` button\n4. And add a new configuration when clicking on the `Add item` button\n5. Select the `elastic` in the `type` selector field\n6. Jump to `Exporter config`\n7. Set the following values: `Cluster URI` -> `http://localhost:9200`\n\nThen test your configuration by clicking on the `Check connection` button. This should output a modal with the Elasticsearch version and the number of loaded docs.\n\nSave at the bottom of the page and enable the exporter (on the top of the page or in list of exporters).\n\n### Testing your configuration\n\nOne simple way to test is to setup the reading of our Elasticsearch instance by Otoroshi.\n\nNavigate to the danger zone (click on the cog on the top right and scroll to `danger zone`). Jump to the `Analytics: Elastic dashboard datasource (read)` section.\n\nSet the following values : `Cluster URI` -> `http://localhost:9200`\n\nThen click on the `Check connection`. This should ouput the same result as the previous part. Save the global configuration and navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/stats](http://otoroshi.oto.tools:8080/bo/dashboard/stats) { open=new }.\n\nThis should output a list of graphs.\n\n### Advanced usage\n\nBy default, an exporter handle all events from Otoroshi. In some case, you need to filter the events to send to elasticsearch.\n\nTo filter the events, jump to the `Filtering and projection` field in exporter view. Otoroshi supports to include a kind of events or to exclude a list of events (if you want to deep learn about this section, read this @ref:[part](../entities/data-exporters.md#matching-and-projections)). \n\nAn example which keep only events with a field `@type` of value `AlertEvent`:\n```json\n{\n \"include\": [\n { \"@type\": \"AlertEvent\" }\n ],\n \"exclude\": []\n}\n```\nAn example which exclude only events with a field `@type` of value `GatewayEvent` :\n```json\n{\n \"exclude\": [\n { \"@type\": \"GatewayEvent\" }\n ],\n \"include\": []\n}\n```\n\nThe next field is the **Projection**. This field is a json when you can list the fields to keep for each event.\n\n```json\n{\n \"@type\": true,\n \"@timestamp\": true,\n \"@id\": true\n}\n```\n\nWith this example, only `@type`, `@timestamp` and `@id` will be send to ES.\n\n### Debug your configuration\n\n#### Missing user rights on Elasticsearch\n\nWhen creating an exporter, Otoroshi try to join the index route of the elasticsearch instance. If you have a specific management access rights on Elasticsearch, you have two possiblities :\n\n- set a full access to the user used in Otoroshi for write in Elasticsearch\n- set the version of Elasticsearch inside the `Version` field of your exporter.\n\n#### None event appear in your Elasticsearch\n\nWhen creating an exporter, Otoroshi try to push the index template on Elasticsearch. If the post failed, Otoroshi will fail for each push of events and your database will keep empty. \n\nTo fix this problem, you can try to send the index template with the `Manually apply index template` button in your exporter."},{"name":"import-export-otoroshi-datastore.md","id":"/how-to-s/import-export-otoroshi-datastore.md","url":"/how-to-s/import-export-otoroshi-datastore.html","title":"Import and export Otoroshi datastore","content":"# Import and export Otoroshi datastore\n\n### Start Otoroshi with an initial datastore\n\nLet's start by downloading the latest Otoroshi\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nBy default, Otoroshi starts with domain `oto.tools` that targets `127.0.0.1` Now you are almost ready to run Otoroshi for the first time, we want run it with an initial data.\n\nTo do that, you need to add the **otoroshi.importFrom** setting to the Otoroshi configuration (of `$APP_IMPORT_FROM` env). It can be a file path or a URL. The content of the initial datastore can look something like the following.\n\n```json\n{\n \"label\": \"Otoroshi initial datastore\",\n \"admins\": [],\n \"simpleAdmins\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"username\": \"admin@otoroshi.io\",\n \"password\": \"$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.\",\n \"label\": \"Otoroshi Admin\",\n \"createdAt\": 1634651307724,\n \"type\": \"SIMPLE\",\n \"metadata\": {},\n \"tags\": [],\n \"rights\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ]\n }\n ],\n \"serviceGroups\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"admin-api-group\",\n \"name\": \"Otoroshi Admin Api group\",\n \"description\": \"No description\",\n \"tags\": [],\n \"metadata\": {}\n },\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"default\",\n \"name\": \"default-group\",\n \"description\": \"The default service group\",\n \"tags\": [],\n \"metadata\": {}\n }\n ],\n \"apiKeys\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"clientId\": \"admin-api-apikey-id\",\n \"clientSecret\": \"admin-api-apikey-secret\",\n \"clientName\": \"Otoroshi Backoffice ApiKey\",\n \"description\": \"The apikey use by the Otoroshi UI\",\n \"authorizedGroup\": \"admin-api-group\",\n \"authorizedEntities\": [\n \"group_admin-api-group\"\n ],\n \"enabled\": true,\n \"readOnly\": false,\n \"allowClientIdOnly\": false,\n \"throttlingQuota\": 10000,\n \"dailyQuota\": 10000000,\n \"monthlyQuota\": 10000000,\n \"constrainedServicesOnly\": false,\n \"restrictions\": {\n \"enabled\": false,\n \"allowLast\": true,\n \"allowed\": [],\n \"forbidden\": [],\n \"notFound\": []\n },\n \"rotation\": {\n \"enabled\": false,\n \"rotationEvery\": 744,\n \"gracePeriod\": 168,\n \"nextSecret\": null\n },\n \"validUntil\": null,\n \"tags\": [],\n \"metadata\": {}\n }\n ],\n \"serviceDescriptors\": [\n {\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"id\": \"admin-api-service\",\n \"groupId\": \"admin-api-group\",\n \"groups\": [\n \"admin-api-group\"\n ],\n \"name\": \"otoroshi-admin-api\",\n \"description\": \"\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"otoroshi-api\",\n \"targetsLoadBalancing\": {\n \"type\": \"RoundRobin\"\n },\n \"targets\": [\n {\n \"host\": \"127.0.0.1:8080\",\n \"scheme\": \"http\",\n \"weight\": 1,\n \"mtlsConfig\": {\n \"certs\": [],\n \"trustedCerts\": [],\n \"mtls\": false,\n \"loose\": false,\n \"trustAll\": false\n },\n \"tags\": [],\n \"metadata\": {},\n \"protocol\": \"HTTP/1.1\",\n \"predicate\": {\n \"type\": \"AlwaysMatch\"\n },\n \"ipAddress\": null\n }\n ],\n \"root\": \"/\",\n \"matchingRoot\": null,\n \"stripPath\": true,\n \"localHost\": \"127.0.0.1:8080\",\n \"localScheme\": \"http\",\n \"redirectToLocal\": false,\n \"enabled\": true,\n \"userFacing\": false,\n \"privateApp\": false,\n \"forceHttps\": false,\n \"logAnalyticsOnServer\": false,\n \"useAkkaHttpClient\": true,\n \"useNewWSClient\": false,\n \"tcpUdpTunneling\": false,\n \"detectApiKeySooner\": false,\n \"maintenanceMode\": false,\n \"buildMode\": false,\n \"strictlyPrivate\": false,\n \"enforceSecureCommunication\": true,\n \"sendInfoToken\": true,\n \"sendStateChallenge\": true,\n \"sendOtoroshiHeadersBack\": true,\n \"readOnly\": false,\n \"xForwardedHeaders\": false,\n \"overrideHost\": true,\n \"allowHttp10\": true,\n \"letsEncrypt\": false,\n \"secComHeaders\": {\n \"claimRequestName\": null,\n \"stateRequestName\": null,\n \"stateResponseName\": null\n },\n \"secComTtl\": 30000,\n \"secComVersion\": 1,\n \"secComInfoTokenVersion\": \"Legacy\",\n \"secComExcludedPatterns\": [],\n \"securityExcludedPatterns\": [],\n \"publicPatterns\": [\n \"/health\",\n \"/metrics\"\n ],\n \"privatePatterns\": [],\n \"additionalHeaders\": {\n \"Host\": \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"additionalHeadersOut\": {},\n \"missingOnlyHeadersIn\": {},\n \"missingOnlyHeadersOut\": {},\n \"removeHeadersIn\": [],\n \"removeHeadersOut\": [],\n \"headersVerification\": {},\n \"matchingHeaders\": {},\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"api\": {\n \"exposeApi\": false\n },\n \"healthCheck\": {\n \"enabled\": false,\n \"url\": \"/\"\n },\n \"clientConfig\": {\n \"useCircuitBreaker\": true,\n \"retries\": 1,\n \"maxErrors\": 20,\n \"retryInitialDelay\": 50,\n \"backoffFactor\": 2,\n \"callTimeout\": 30000,\n \"callAndStreamTimeout\": 120000,\n \"connectionTimeout\": 10000,\n \"idleTimeout\": 60000,\n \"globalTimeout\": 30000,\n \"sampleInterval\": 2000,\n \"proxy\": {},\n \"customTimeouts\": [],\n \"cacheConnectionSettings\": {\n \"enabled\": false,\n \"queueSize\": 2048\n }\n },\n \"canary\": {\n \"enabled\": false,\n \"traffic\": 0.2,\n \"targets\": [],\n \"root\": \"/\"\n },\n \"gzip\": {\n \"enabled\": false,\n \"excludedPatterns\": [],\n \"whiteList\": [\n \"text/*\",\n \"application/javascript\",\n \"application/json\"\n ],\n \"blackList\": [],\n \"bufferSize\": 8192,\n \"chunkedThreshold\": 102400,\n \"compressionLevel\": 5\n },\n \"metadata\": {},\n \"tags\": [],\n \"chaosConfig\": {\n \"enabled\": false,\n \"largeRequestFaultConfig\": null,\n \"largeResponseFaultConfig\": null,\n \"latencyInjectionFaultConfig\": null,\n \"badResponsesFaultConfig\": null\n },\n \"jwtVerifier\": {\n \"type\": \"ref\",\n \"ids\": [],\n \"id\": null,\n \"enabled\": false,\n \"excludedPatterns\": []\n },\n \"secComSettings\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComUseSameAlgo\": true,\n \"secComAlgoChallengeOtoToBack\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComAlgoChallengeBackToOto\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"secComAlgoInfoToken\": {\n \"type\": \"HSAlgoSettings\",\n \"size\": 512,\n \"secret\": \"secret\",\n \"base64\": false\n },\n \"cors\": {\n \"enabled\": false,\n \"allowOrigin\": \"*\",\n \"exposeHeaders\": [],\n \"allowHeaders\": [],\n \"allowMethods\": [],\n \"excludedPatterns\": [],\n \"maxAge\": null,\n \"allowCredentials\": true\n },\n \"redirection\": {\n \"enabled\": false,\n \"code\": 303,\n \"to\": \"https://www.otoroshi.io\"\n },\n \"authConfigRef\": null,\n \"clientValidatorRef\": null,\n \"transformerRef\": null,\n \"transformerRefs\": [],\n \"transformerConfig\": {},\n \"apiKeyConstraints\": {\n \"basicAuth\": {\n \"enabled\": true,\n \"headerName\": null,\n \"queryName\": null\n },\n \"customHeadersAuth\": {\n \"enabled\": true,\n \"clientIdHeaderName\": null,\n \"clientSecretHeaderName\": null\n },\n \"clientIdAuth\": {\n \"enabled\": true,\n \"headerName\": null,\n \"queryName\": null\n },\n \"jwtAuth\": {\n \"enabled\": true,\n \"secretSigned\": true,\n \"keyPairSigned\": true,\n \"includeRequestAttributes\": false,\n \"maxJwtLifespanSecs\": null,\n \"headerName\": null,\n \"queryName\": null,\n \"cookieName\": null\n },\n \"routing\": {\n \"noneTagIn\": [],\n \"oneTagIn\": [],\n \"allTagsIn\": [],\n \"noneMetaIn\": {},\n \"oneMetaIn\": {},\n \"allMetaIn\": {},\n \"noneMetaKeysIn\": [],\n \"oneMetaKeyIn\": [],\n \"allMetaKeysIn\": []\n }\n },\n \"restrictions\": {\n \"enabled\": false,\n \"allowLast\": true,\n \"allowed\": [],\n \"forbidden\": [],\n \"notFound\": []\n },\n \"accessValidator\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excludedPatterns\": []\n },\n \"preRouting\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excludedPatterns\": []\n },\n \"plugins\": {\n \"enabled\": false,\n \"refs\": [],\n \"config\": {},\n \"excluded\": []\n },\n \"hosts\": [\n \"otoroshi-api.oto.tools\"\n ],\n \"paths\": [],\n \"handleLegacyDomain\": true,\n \"issueCert\": false,\n \"issueCertCA\": null\n }\n ],\n \"errorTemplates\": [],\n \"jwtVerifiers\": [],\n \"authConfigs\": [],\n \"certificates\": [],\n \"clientValidators\": [],\n \"scripts\": [],\n \"tcpServices\": [],\n \"dataExporters\": [],\n \"tenants\": [\n {\n \"id\": \"default\",\n \"name\": \"Default organization\",\n \"description\": \"The default organization\",\n \"metadata\": {},\n \"tags\": []\n }\n ],\n \"teams\": [\n {\n \"id\": \"default\",\n \"tenant\": \"default\",\n \"name\": \"Default Team\",\n \"description\": \"The default Team of the default organization\",\n \"metadata\": {},\n \"tags\": []\n }\n ]\n}\n```\n\nRun an Otoroshi with the previous file as parameter.\n\n```sh\njava \\\n -Dotoroshi.adminPassword=password \\\n -Dotoroshi.importFrom=./initial-state.json \\\n -jar otoroshi.jar \n```\n\nThis should display\n\n```sh\n...\n[info] otoroshi-env - Importing from: ./initial-state.json\n[info] otoroshi-env - Successful import !\n...\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n...\n```\n\n> Warning : when you using Otoroshi with a datastore different from file or in-memory, Otoroshi will not reload the initialization script. If you expected, you have to manually clean your store.\n\n### Export the current datastore via the danger zone\n\nWhen Otoroshi is running, you can backup the global configuration store from the UI. Navigate to your instance (in our case @link:[http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) { open=new }) and scroll to the bottom page. \n\nClick on `Full export` button to download the full global configuration.\n\n### Import a datastore from file via the danger zone\n\nWhen Otoroshi is running, you can recover a global configuration from the UI. Navigate to your instance (in our case @link:[http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) { open=new }) and scroll to the bottom of the page. \n\nClick on `Recover from a full export file` button to apply all configurations from a file.\n\n### Export the current datastore with the Admin API\n\nOtoroshi exposes his own Admin API to manage Otoroshi resources. To call this api, you need to have an api key with the rights on `Otoroshi Admin Api group`. This group includes the `Otoroshi-admin-api` service that you can found on the services page. \n\nBy default, and with our initial configuration, Otoroshi has already created an api key named `Otoroshi Backoffice ApiKey`. You can verify the rights of an api key on its page by checking the `Authorized On` field (you should find the `Otoroshi Admin Api group` inside).\n\nThe default api key id and secret are `admin-api-apikey-id` and `admin-api-apikey-secret`.\n\nRun the next command with these values.\n\n```sh\ncurl \\\n -H 'Content-Type: application/json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json'\n```\n\nWhen calling the `/api/otoroshi.json`, the return should be the current datastore including the service descriptors, the api keys, all others resources like certificates and authentification modules, and the the global config (representing the form of the danger zone).\n\n### Import the current datastore with the Admin API\n\nAs the same way of previous section, you can erase the current datastore with a POST request. The route is the same : `/api/otoroshi.json`.\n\n```sh\ncurl \\\n -X POST \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"label\" : \"Otoroshi export\",\n \"dateRaw\" : 1634714811217,\n \"date\" : \"2021-10-20 09:26:51\",\n \"stats\" : {\n \"calls\" : 4,\n \"dataIn\" : 0,\n \"dataOut\" : 97991\n },\n \"config\" : {\n \"tags\" : [ ],\n \"letsEncryptSettings\" : {\n \"enabled\" : false,\n \"server\" : \"acme://letsencrypt.org/staging\",\n \"emails\" : [ ],\n \"contacts\" : [ ],\n \"publicKey\" : \"\",\n \"privateKey\" : \"\"\n },\n \"lines\" : [ \"prod\" ],\n \"maintenanceMode\" : false,\n \"enableEmbeddedMetrics\" : true,\n \"streamEntityOnly\" : true,\n \"autoLinkToDefaultGroup\" : true,\n \"limitConcurrentRequests\" : false,\n \"maxConcurrentRequests\" : 1000,\n \"maxHttp10ResponseSize\" : 4194304,\n \"useCircuitBreakers\" : true,\n \"apiReadOnly\" : false,\n \"u2fLoginOnly\" : false,\n \"trustXForwarded\" : true,\n \"ipFiltering\" : {\n \"whitelist\" : [ ],\n \"blacklist\" : [ ]\n },\n \"throttlingQuota\" : 10000000,\n \"perIpThrottlingQuota\" : 10000000,\n \"analyticsWebhooks\" : [ ],\n \"alertsWebhooks\" : [ ],\n \"elasticWritesConfigs\" : [ ],\n \"elasticReadsConfig\" : null,\n \"alertsEmails\" : [ ],\n \"logAnalyticsOnServer\" : false,\n \"useAkkaHttpClient\" : false,\n \"endlessIpAddresses\" : [ ],\n \"statsdConfig\" : null,\n \"kafkaConfig\" : {\n \"servers\" : [ ],\n \"keyPass\" : null,\n \"keystore\" : null,\n \"truststore\" : null,\n \"topic\" : \"otoroshi-events\",\n \"mtlsConfig\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n },\n \"backOfficeAuthRef\" : null,\n \"mailerSettings\" : {\n \"type\" : \"none\"\n },\n \"cleverSettings\" : null,\n \"maxWebhookSize\" : 100,\n \"middleFingers\" : false,\n \"maxLogsSize\" : 10000,\n \"otoroshiId\" : \"83539cbca-76ee-4abc-ad31-a4794e873848\",\n \"snowMonkeyConfig\" : {\n \"enabled\" : false,\n \"outageStrategy\" : \"OneServicePerGroup\",\n \"includeUserFacingDescriptors\" : false,\n \"dryRun\" : false,\n \"timesPerDay\" : 1,\n \"startTime\" : \"09:00:00.000\",\n \"stopTime\" : \"23:59:59.000\",\n \"outageDurationFrom\" : 600000,\n \"outageDurationTo\" : 3600000,\n \"targetGroups\" : [ ],\n \"chaosConfig\" : {\n \"enabled\" : true,\n \"largeRequestFaultConfig\" : null,\n \"largeResponseFaultConfig\" : null,\n \"latencyInjectionFaultConfig\" : {\n \"ratio\" : 0.2,\n \"from\" : 500,\n \"to\" : 5000\n },\n \"badResponsesFaultConfig\" : {\n \"ratio\" : 0.2,\n \"responses\" : [ {\n \"status\" : 502,\n \"body\" : \"{\\\"error\\\":\\\"Nihonzaru everywhere ...\\\"}\",\n \"headers\" : {\n \"Content-Type\" : \"application/json\"\n }\n } ]\n }\n }\n },\n \"scripts\" : {\n \"enabled\" : false,\n \"transformersRefs\" : [ ],\n \"transformersConfig\" : { },\n \"validatorRefs\" : [ ],\n \"validatorConfig\" : { },\n \"preRouteRefs\" : [ ],\n \"preRouteConfig\" : { },\n \"sinkRefs\" : [ ],\n \"sinkConfig\" : { },\n \"jobRefs\" : [ ],\n \"jobConfig\" : { }\n },\n \"geolocationSettings\" : {\n \"type\" : \"none\"\n },\n \"userAgentSettings\" : {\n \"enabled\" : false\n },\n \"autoCert\" : {\n \"enabled\" : false,\n \"replyNicely\" : false,\n \"caRef\" : null,\n \"allowed\" : [ ],\n \"notAllowed\" : [ ]\n },\n \"tlsSettings\" : {\n \"defaultDomain\" : null,\n \"randomIfNotFound\" : false,\n \"includeJdkCaServer\" : true,\n \"includeJdkCaClient\" : true,\n \"trustedCAsServer\" : [ ]\n },\n \"plugins\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excluded\" : [ ]\n },\n \"metadata\" : { }\n },\n \"admins\" : [ ],\n \"simpleAdmins\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"username\" : \"admin@otoroshi.io\",\n \"password\" : \"$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.\",\n \"label\" : \"Otoroshi Admin\",\n \"createdAt\" : 1634651307724,\n \"type\" : \"SIMPLE\",\n \"metadata\" : { },\n \"tags\" : [ ],\n \"rights\" : [ {\n \"tenant\" : \"*:rw\",\n \"teams\" : [ \"*:rw\" ]\n } ]\n } ],\n \"serviceGroups\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"admin-api-group\",\n \"name\" : \"Otoroshi Admin Api group\",\n \"description\" : \"No description\",\n \"tags\" : [ ],\n \"metadata\" : { }\n }, {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"default\",\n \"name\" : \"default-group\",\n \"description\" : \"The default service group\",\n \"tags\" : [ ],\n \"metadata\" : { }\n } ],\n \"apiKeys\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"clientId\" : \"admin-api-apikey-id\",\n \"clientSecret\" : \"admin-api-apikey-secret\",\n \"clientName\" : \"Otoroshi Backoffice ApiKey\",\n \"description\" : \"The apikey use by the Otoroshi UI\",\n \"authorizedGroup\" : \"admin-api-group\",\n \"authorizedEntities\" : [ \"group_admin-api-group\" ],\n \"enabled\" : true,\n \"readOnly\" : false,\n \"allowClientIdOnly\" : false,\n \"throttlingQuota\" : 10000,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"constrainedServicesOnly\" : false,\n \"restrictions\" : {\n \"enabled\" : false,\n \"allowLast\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"notFound\" : [ ]\n },\n \"rotation\" : {\n \"enabled\" : false,\n \"rotationEvery\" : 744,\n \"gracePeriod\" : 168,\n \"nextSecret\" : null\n },\n \"validUntil\" : null,\n \"tags\" : [ ],\n \"metadata\" : { }\n } ],\n \"serviceDescriptors\" : [ {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"admin-api-service\",\n \"groupId\" : \"admin-api-group\",\n \"groups\" : [ \"admin-api-group\" ],\n \"name\" : \"otoroshi-admin-api\",\n \"description\" : \"\",\n \"env\" : \"prod\",\n \"domain\" : \"oto.tools\",\n \"subdomain\" : \"otoroshi-api\",\n \"targetsLoadBalancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"targets\" : [ {\n \"host\" : \"127.0.0.1:8080\",\n \"scheme\" : \"http\",\n \"weight\" : 1,\n \"mtlsConfig\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n },\n \"tags\" : [ ],\n \"metadata\" : { },\n \"protocol\" : \"HTTP/1.1\",\n \"predicate\" : {\n \"type\" : \"AlwaysMatch\"\n },\n \"ipAddress\" : null\n } ],\n \"root\" : \"/\",\n \"matchingRoot\" : null,\n \"stripPath\" : true,\n \"localHost\" : \"127.0.0.1:8080\",\n \"localScheme\" : \"http\",\n \"redirectToLocal\" : false,\n \"enabled\" : true,\n \"userFacing\" : false,\n \"privateApp\" : false,\n \"forceHttps\" : false,\n \"logAnalyticsOnServer\" : false,\n \"useAkkaHttpClient\" : true,\n \"useNewWSClient\" : false,\n \"tcpUdpTunneling\" : false,\n \"detectApiKeySooner\" : false,\n \"maintenanceMode\" : false,\n \"buildMode\" : false,\n \"strictlyPrivate\" : false,\n \"enforceSecureCommunication\" : true,\n \"sendInfoToken\" : true,\n \"sendStateChallenge\" : true,\n \"sendOtoroshiHeadersBack\" : true,\n \"readOnly\" : false,\n \"xForwardedHeaders\" : false,\n \"overrideHost\" : true,\n \"allowHttp10\" : true,\n \"letsEncrypt\" : false,\n \"secComHeaders\" : {\n \"claimRequestName\" : null,\n \"stateRequestName\" : null,\n \"stateResponseName\" : null\n },\n \"secComTtl\" : 30000,\n \"secComVersion\" : 1,\n \"secComInfoTokenVersion\" : \"Legacy\",\n \"secComExcludedPatterns\" : [ ],\n \"securityExcludedPatterns\" : [ ],\n \"publicPatterns\" : [ \"/health\", \"/metrics\" ],\n \"privatePatterns\" : [ ],\n \"additionalHeaders\" : {\n \"Host\" : \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"additionalHeadersOut\" : { },\n \"missingOnlyHeadersIn\" : { },\n \"missingOnlyHeadersOut\" : { },\n \"removeHeadersIn\" : [ ],\n \"removeHeadersOut\" : [ ],\n \"headersVerification\" : { },\n \"matchingHeaders\" : { },\n \"ipFiltering\" : {\n \"whitelist\" : [ ],\n \"blacklist\" : [ ]\n },\n \"api\" : {\n \"exposeApi\" : false\n },\n \"healthCheck\" : {\n \"enabled\" : false,\n \"url\" : \"/\"\n },\n \"clientConfig\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n },\n \"canary\" : {\n \"enabled\" : false,\n \"traffic\" : 0.2,\n \"targets\" : [ ],\n \"root\" : \"/\"\n },\n \"gzip\" : {\n \"enabled\" : false,\n \"excludedPatterns\" : [ ],\n \"whiteList\" : [ \"text/*\", \"application/javascript\", \"application/json\" ],\n \"blackList\" : [ ],\n \"bufferSize\" : 8192,\n \"chunkedThreshold\" : 102400,\n \"compressionLevel\" : 5\n },\n \"metadata\" : { },\n \"tags\" : [ ],\n \"chaosConfig\" : {\n \"enabled\" : false,\n \"largeRequestFaultConfig\" : null,\n \"largeResponseFaultConfig\" : null,\n \"latencyInjectionFaultConfig\" : null,\n \"badResponsesFaultConfig\" : null\n },\n \"jwtVerifier\" : {\n \"type\" : \"ref\",\n \"ids\" : [ ],\n \"id\" : null,\n \"enabled\" : false,\n \"excludedPatterns\" : [ ]\n },\n \"secComSettings\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComUseSameAlgo\" : true,\n \"secComAlgoChallengeOtoToBack\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComAlgoChallengeBackToOto\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"secComAlgoInfoToken\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"cors\" : {\n \"enabled\" : false,\n \"allowOrigin\" : \"*\",\n \"exposeHeaders\" : [ ],\n \"allowHeaders\" : [ ],\n \"allowMethods\" : [ ],\n \"excludedPatterns\" : [ ],\n \"maxAge\" : null,\n \"allowCredentials\" : true\n },\n \"redirection\" : {\n \"enabled\" : false,\n \"code\" : 303,\n \"to\" : \"https://www.otoroshi.io\"\n },\n \"authConfigRef\" : null,\n \"clientValidatorRef\" : null,\n \"transformerRef\" : null,\n \"transformerRefs\" : [ ],\n \"transformerConfig\" : { },\n \"apiKeyConstraints\" : {\n \"basicAuth\" : {\n \"enabled\" : true,\n \"headerName\" : null,\n \"queryName\" : null\n },\n \"customHeadersAuth\" : {\n \"enabled\" : true,\n \"clientIdHeaderName\" : null,\n \"clientSecretHeaderName\" : null\n },\n \"clientIdAuth\" : {\n \"enabled\" : true,\n \"headerName\" : null,\n \"queryName\" : null\n },\n \"jwtAuth\" : {\n \"enabled\" : true,\n \"secretSigned\" : true,\n \"keyPairSigned\" : true,\n \"includeRequestAttributes\" : false,\n \"maxJwtLifespanSecs\" : null,\n \"headerName\" : null,\n \"queryName\" : null,\n \"cookieName\" : null\n },\n \"routing\" : {\n \"noneTagIn\" : [ ],\n \"oneTagIn\" : [ ],\n \"allTagsIn\" : [ ],\n \"noneMetaIn\" : { },\n \"oneMetaIn\" : { },\n \"allMetaIn\" : { },\n \"noneMetaKeysIn\" : [ ],\n \"oneMetaKeyIn\" : [ ],\n \"allMetaKeysIn\" : [ ]\n }\n },\n \"restrictions\" : {\n \"enabled\" : false,\n \"allowLast\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"notFound\" : [ ]\n },\n \"accessValidator\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excludedPatterns\" : [ ]\n },\n \"preRouting\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excludedPatterns\" : [ ]\n },\n \"plugins\" : {\n \"enabled\" : false,\n \"refs\" : [ ],\n \"config\" : { },\n \"excluded\" : [ ]\n },\n \"hosts\" : [ \"otoroshi-api.oto.tools\" ],\n \"paths\" : [ ],\n \"handleLegacyDomain\" : true,\n \"issueCert\" : false,\n \"issueCertCA\" : null\n } ],\n \"errorTemplates\" : [ ],\n \"jwtVerifiers\" : [ ],\n \"authConfigs\" : [ ],\n \"certificates\" : [],\n \"clientValidators\" : [ ],\n \"scripts\" : [ ],\n \"tcpServices\" : [ ],\n \"dataExporters\" : [ ],\n \"tenants\" : [ {\n \"id\" : \"default\",\n \"name\" : \"Default organization\",\n \"description\" : \"The default organization\",\n \"metadata\" : { },\n \"tags\" : [ ]\n } ],\n \"teams\" : [ {\n \"id\" : \"default\",\n \"tenant\" : \"default\",\n \"name\" : \"Default Team\",\n \"description\" : \"The default Team of the default organization\",\n \"metadata\" : { },\n \"tags\" : [ ]\n } ]\n }' \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \n```\n\nThis should output :\n\n```json\n{ \"done\":true }\n```\n\n> Note : be very carefully with this POST command. If you send a wrong JSON, you risk breaking your instance.\n\nThe second way is to send the same configuration but from a file. You can pass two kind of file : a `json` file or a `ndjson` file. Both files are available as export methods on the danger zone.\n\n```sh\n# the curl is run from a folder containing the initial-state.json file \ncurl -X POST \\\n -H \"Content-Type: application/json\" \\\n -d @./initial-state.json \\\n 'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret\n```\n\nThis should output :\n\n```json\n{ \"done\":true }\n```\n\n> Note: To send a ndjson file, you have to set the Content-Type header at `application/x-ndjson`"},{"name":"index.md","id":"/how-to-s/index.md","url":"/how-to-s/index.html","title":"How to's","content":"# How to's\n\nin this section, we will explain some mainstream Otoroshi usage scenario's \n\n* @ref:[End-to-end mTLS](./end-to-end-mtls.md)\n* @ref:[Send alerts by emails](./export-alerts-using-mailgun.md)\n* @ref:[Export events to Elasticsearch](./export-events-to-elastic.md)\n* @ref:[Import/export Otoroshi datastore](./import-export-otoroshi-datastore.md)\n* @ref:[Secure an app with Auth0](./secure-app-with-auth0.md)\n* @ref:[Secure an app with Keycloak](./secure-app-with-keycloak.md)\n* @ref:[Secure an app with LDAP](./secure-app-with-ldap.md)\n* @ref:[Secure an api with apikeys](./secure-with-apikey.md)\n* @ref:[Secure an app with OAuth1](./secure-with-oauth1-client.md)\n* @ref:[Secure an api with OAuth2 client_credentials flow](./secure-with-oauth2-client-credentials.md)\n* @ref:[Setup an Otoroshi cluster](./setup-otoroshi-cluster.md)\n* @ref:[TLS termination using Let's Encrypt](./tls-using-lets-encrypt.md)\n* @ref:[Secure an app with jwt verifiers](./secure-an-app-with-jwt-verifiers.md)\n* @ref:[Secure the communication between a backend app and Otoroshi](./secure-the-communication-between-a-backend-app-and-otoroshi.md)\n* @ref:[TLS termination using your own certificates](./tls-termination-using-own-certificates.md)\n* @ref:[The resources loader](./resources-loader.md)\n* @ref:[Log levels customization](./custom-log-levels.md)\n* @ref:[Initial state customization](./custom-initial-state.md)\n\n@@@ index\n\n* [End-to-end mTLS](./end-to-end-mtls.md)\n* [Send alerts by emails](./export-alerts-using-mailgun.md)\n* [Export events to Elasticsearch](./export-events-to-elastic.md)\n* [Import/export Otoroshi datastore](./import-export-otoroshi-datastore.md)\n* [Secure an app with Auth0](./secure-app-with-auth0.md)\n* [Secure an app with Keycloak](./secure-app-with-keycloak.md)\n* [Secure an app with LDAP](./secure-app-with-ldap.md)\n* [Secure an api with apikeys](./secure-with-apikey.md)\n* [Secure an app with OAuth1](./secure-with-oauth1-client.md)\n* [Secure an api with OAuth2 client_credentials flow](./secure-with-oauth2-client-credentials.md)\n* [Setup an Otoroshi cluster](./setup-otoroshi-cluster.md)\n* [TLS termination using Let's Encrypt](./tls-using-lets-encrypt.md)\n* [Secure an app with jwt verifiers](./secure-an-app-with-jwt-verifiers.md)\n* [Secure the communication between a backend app and Otoroshi](./secure-the-communication-between-a-backend-app-and-otoroshi.md)\n* [TLS termination using your own certificates](./tls-termination-using-own-certificates.md)\n* [The resources loader](./resources-loader.md)\n* [Log levels customization](./custom-log-levels.md)\n* [Initial state customization](./custom-initial-state.md)\n\n@@@"},{"name":"resources-loader.md","id":"/how-to-s/resources-loader.md","url":"/how-to-s/resources-loader.html","title":"The resources loader","content":"# The resources loader\n\nThe resources loader is a tool to create an Otoroshi resource from a raw content. This content can be found on each Otoroshi resources pages (services descriptors, apikeys, certificates, etc ...). To get the content of a resource as file, you can use the two export buttons, one to export as JSON format and the other as YAML format.\n\nOnce exported, the content of the resource can be import with the resource loader. You can import single or multiples resources on one time, as JSON and YAML format.\n\nThe resource loader is available on this route [`bo/dashboard/resources-loader`](http://otoroshi.oto.tools:8080/bo/dashboard/resources-loader).\n\nOn this page, you can paste the content of your resources and click on **Load resources**.\n\nFor each detected resource, the loader will display :\n\n* a resource name corresponding to the field `name` \n* a resource type corresponding to the type of created resource (ServiceDescriptor, ApiKey, Certificate, etc)\n* a toggle to choose if you want to include the element for the creation step\n* the updated status by the creation process\n\nOnce you have selected the resources to create, you can **Import selected resources**.\n\nOnce generated, all status will be updated. If all is working, the status will be equals to done.\n\nIf you want to get back to the initial page, you can use the **restart** button."},{"name":"secure-an-app-with-jwt-verifiers.md","id":"/how-to-s/secure-an-app-with-jwt-verifiers.md","url":"/how-to-s/secure-an-app-with-jwt-verifiers.html","title":"Secure an api with jwt verifiers","content":"# Secure an api with jwt verifiers\n\nA Jwt verifier is the guard which check the signature of tokens present in incoming requests on a service. It can be a simple verifier, a tokens generator, or extend to be a verifier and a tokens generator.\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Your first jwt verifier : a verifier of tokens\n\nLet's start navigating the @link:[page of verifier creation](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers/add) { open=new }. By default, the type of jwt verifier is a **Verify JWT token**.\n\nCreate the following verifier : \n\n* Set `simple-jwt-verifier` as `Name`\n* Set `My simple jwt verifier` as `Description`\n* We expect in entry a token in a specific header. Set `Authorization` as `Header name`\n* Select `Hmac + SHA` as `Algo` (for this example, we expect tokens with a symetric signature)\n* Set `otoroshi` as `Hmac secret`\n* Remove the default field in `Verify token fields` array\n* Create your verifier when clicking on `Create and stay on this Jwt verifier` button.\n\nOnce created, navigate to the simple service (created in @ref:[Before you start](#before-you-start) section) and jump to the `JWT tokens verification` section.\n\nIn the verifiers list, choose the `simple-jwt-verifier` and `enabled` the section.\n\nSave your service and try to call the service.\n```sh\ncurl -X GET 'http://myservice.oto.tools:8080/' --include\n```\n\nThis should output : \n```json\n{\n \"Otoroshi-Error\": \"error.expected.token.not.found\"\n}\n```\n\nA simple way to generate a token is to use @link:[jwt.io](http://jwt.io) { open=new }. Once navigate, define `HS512` as `alg` in header section, and insert `otoroshi` as verify signature secret. \n\nOnce created, copy-paste the token from jwt.io to the Authorization header and call our service.\n\n```sh\n# replace xxxx by the generated token\ncurl -X GET \\\n -H \"Authorization: xxxx\" \\\n 'http://myservice.oto.tools:8080'\n```\n\nThis should output a json with `authorization` in headers field. His value is exactly the same as the passed token.\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.otoroshi.io\",\n \"authorization\": \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.ipDFgkww51mSaSg_199BMRj4gK20LGz_czozu3u8rCFFO1X20MwcabSqEzUc0q4qQ4rjTxjoR4HeUDVcw8BxoQ\",\n ...\n }\n}\n```\n\n### Verify and generate a new token\n\nAn other feature is to verify the entry token and generate a new token, with a different signature and news claims. \n\nLet's start by extending the @link:[previous verifier](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers) { open=new }.\n\n1. Jump to the `Verif Strategy` field and select `Verify and re-sign JWT token`. \n2. Edit the name with `jwt-verify-and-resign`\n3. Remove the default field in `Verify token fields` array\n4. Change the second `Hmac secret` in `Re-sign settings` section with `otoroshi-internal-secret`\n5. Save your verifier.\n\n> Note : the name of the verifier doesn't impact the identifier. So you can save the changes of your verifier without modifying the identifier used in your call. \n\n```sh\n# replace xxxx by the generated token\ncurl -X GET \\\n -H \"Authorization: xxxx\" \\\n 'http://myservice.oto.tools:8080'\n```\n\nThis should output a json with `authorization` in headers field. This time, the value are different and you can check his signature on @link:[jwt.io](https://jwt.io) { open=new } (the expected secret of the generated token is **otoroshi-internal-secret**)\n\n\n\n### Verify, transform and generate a new token\n\nThe most advanced verifier is able to do the same as the previous ones, with the ability to configure the token generation (claims, output header name).\n\nLet's start by extending the @link:[previous verifier](http://otoroshi.oto.tools:8080/bo/dashboard/jwt-verifiers) { open=new }.\n\n1. Jump to the `Verif Strategy` field and select `Verify, transform and re-sign JWT token`. \n\n2. Edit the name with `jwt-verify-transform-and-resign`\n3. Remove the default field in `Verify token fields` array\n4. Change the second `Hmac secret` in `Re-sign settings` section with `otoroshi-internal-secret`\n5. Set `Internal-Authorization` as `Header name`\n6. Set `key` on first field of `Rename token fields` and `from-otoroshi-verifier` on second field\n7. Set `generated-key` and `generated-value` as `Set token fields`\n8. Add `generated_at` and `${date}` as second field of `Set token fields` (Otoroshi supports an @ref:[expression language](../topics/expression-language.md))\n9. Save your verifier and try to call your service again.\n\nThis should output a json with `authorization` in headers field and our generate token in `Internal-Authorization`.\nOnce paste in @link:[jwt.io](https://jwt.io) { open=new }, you should have :\n\n\n\nYou can see, in the payload of your token, the two claims **from-otoroshi-verifier** and **generated-key** added during the generation of the token by the JWT verifier.\n"},{"name":"secure-app-with-auth0.md","id":"/how-to-s/secure-app-with-auth0.md","url":"/how-to-s/secure-app-with-auth0.html","title":"Secure an app with Auth0","content":"# Secure an app with Auth0\n\n### Download Otoroshi\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Configure an Auth0 client\n\nThe first step of this tutorial is to setup an Auth0 application with the information of the instance of our Otoroshi.\n\nNavigate to @link:[https://manage.auth0.com](https://manage.auth0.com) { open=new } (create an account if it's not already done). \n\nLet's create an application when clicking on the **Applications** button on the sidebar. Then click on the **Create application** button on the top right.\n\n1. Choose `Regular Web Applications` as `Application type`\n2. Then set for example `otoroshi-client` as `Name`, and confirm the creation\n3. Jump to the `Settings` tab\n4. Scroll to the `Application URLs` section and add the following url as `Allowed Callback URLs` : `http://otoroshi.oto.tools:8080/backoffice/auth0/callback`\n5. Set `https://otoroshi.oto.tools:8080/` as `Allowed Logout URLs`\n6. Set `https://otoroshi.oto.tools:8080` as `Allowed Web Origins` \n7. Save changes at the bottom of the page.\n\nOnce done, we have a full setup, with a client ID and secret at the top of the page, which authorizes our Otoroshi and redirects the user to the callback url when they log into Auth0.\n\n### Create an Auth0 provider module\n\nLet's back to Otoroshi to create an authentication module with `OAuth2 / OIDC provider` as `type`.\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n1. Click on the cog icon on the top right\n1. Then `Authentication configs` button\n1. And add a new configuration when clicking on the `Add item` button\n2. Select the `OAuth provider` in the type selector field\n3. Then click on `Get from OIDC config` and paste `https://..auth0.com/.well-known/openid-configuration`. Replace the tenant name by the name of your tenant (displayed on the left top of auth0 page), and the region of the tenant (`eu` in my case).\n\nOnce done, set the `Client ID` and the `Client secret` from your Auth0 application. End the configuration with `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Callback URL`.\n\nAt the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs).\n\n### Connect to Otoroshi with Auth0 authentication\n\nTo secure Otoroshi with your Auth0 configuration, we have to register an **Authentication configuration** as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n2. Scroll to the **BackOffice auth. settings**\n3. Select your last Authentication configuration (created in the previous section)\n4. Save the global configuration with the button on the top right\n\n#### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the *Login using third-party* button (or navigate to http://otoroshi.oto.tools:8080)\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the auth0 server login page\n4. Set your account credentials\n5. Good works! You're connected to Otoroshi with an Auth0 module.\n\n### Secure an app with Auth0 authentication\n\nWith the previous configuration, you can secure any of Otoroshi services with it. \n\nThe first step is to apply a little change on the previous configuration. \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs](http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs) { open=new }.\n2. Create a new **Authentication module** configuration with the same values.\n3. Replace the `Callback URL` field to `http://privateapps.oto.tools:8080/privateapps/generic/callback` (we changed this value because the redirection of a connected user by a third-party server is covered by another route by Otoroshi).\n4. Disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n> Note : an Otoroshi service is called **a private app** when it is protected by an Authentication module.\n\nWe can set the Authentication module on the service.\n\n1. Navigate to any created service\n2. Scroll to `Authentication` section\n3. Enable `Enforce user authentication`\n4. Select your Authentication config inside the list\n5. Enable `Strict mode`\n6. Don't forget to save your configuration.\n7. Now you can try to call your defined service and see the Auth0 login page appears.\n\n\n"},{"name":"secure-app-with-keycloak.md","id":"/how-to-s/secure-app-with-keycloak.md","url":"/how-to-s/secure-app-with-keycloak.html","title":"Secure an app with Keycloak","content":"# Secure an app with Keycloak\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Running a keycloak instance with docker\n\n```sh\ndocker run \\\n -p 8080:8080 \\\n -e KEYCLOAK_USER=admin \\\n -e KEYCLOAK_PASSWORD=admin \\\n --name keycloak-server \\\n --detach jboss/keycloak:15.0.1\n```\n\nThis should download the image of keycloak (if you haven't already it) and display the digest of the created container. This command mapped TCP port 8080 in the container to port 8080 of your laptop and created a server with `admin/admin` as admin credentials.\n\nOnce started, you can open a browser on @link:[http://localhost:8080](http://localhost:8080) { open=new } and click on `Administration Console`. Log to your instance with `admin/admin` as credentials.\n\nThe first step is to create a Keycloak client, an entity that can request Keycloak to authenticate a user. Click on the **clients** button on the sidebar, and then on **Create** button at the top right of the view.\n\nFill the client form with the following values.\n\n* `Client ID`: `keycloak-otoroshi-backoffice`\n* `Client Protocol`: `openid-connect`\n* `Root URL`: `http://otoroshi.oto.tools:8080/`\n\nValidate the creation of the client by clicking on the **Save** button.\n\nThe next step is to change the `Access Type` used by default. Jump to the `Access Type` field and select `confidential`. The confidential configuration force the client application to send at Keycloak a client ID and a client Secret. Scroll to the bottom of the page and save the configuration.\n\nNow scroll to the top of your page. Just at the right of the `Settings` tab, a new tab appeared : the `Credentials` page. Click on this tab, and make sure that `Client Id and Secret` is selected as `Client Authenticator` and copy the generated `Secret` to the next part.\n\n### Create a Keycloak provider module\n\n1. Go ahead, and navigate to http://otoroshi.oto.tools:8080\n1. Click on the cog icon on the top right\n1. Then `Authentication configs` button\n1. And add a new configuration when clicking on the `Add item` button\n2. Select the `OAuth2 / OIDC provider` in the type selector field\n3. Set a basic name and description\n\nA simple way to import a Keycloak client is to give the `URL of the OpenID Connect` Otoroshi. By default, keycloak used the next URL : `http://localhost:8080/auth/realms/master/.well-known/openid-configuration`. \n\nClick on the `Get from OIDC config` button and paste the previous link. Once it's done, scroll to the `URLs` section. All URLs has been fill with the values picked from the JSON object returns by the previous URL.\n\nThe only fields to change are : \n\n* `Client ID`: `keycloak-otoroshi-backoffice`\n* `Client Secret`: Paste the secret from the Credentials Keycloak page. In my case, it's something like `90c9bf0b-2c0c-4eb0-aa02-72195beb9da7`\n* `Callback URL`: `http://otoroshi.oto.tools:8080/backoffice/auth0/callback`\n\nAt the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs). Nothing else to change, just save the configuration.\n\n### Connect to Otoroshi with Keycloak authentication\n\nTo secure Otoroshi with your Keycloak configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n1. Scroll to the **BackOffice auth. settings**\n1. Select your last Authentication configuration (created in the previous section)\n1. Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the **Login using third-party** button (or navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new })\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the keycloak login page\n4. Set `admin/admin` as user and trust the user by clicking on `yes` button.\n5. Good work! You're connected to Otoroshi with an Keycloak module.\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n### Visualize an admin user session or a private user session\n\nEach user, wheter connected user to the Otoroshi UI or at a private Otoroshi app, has an own session. As an administrator of Otoroshi, you can visualize via Otoroshi the list of the connected users and their profile.\n\nLet's start by navigating to the `Admin users sessions` page (just @link:[here](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/admin) or when clicking on the cog, and on the `Admins sessions` button at the bottom of the list).\n\nThis page gives a complete view of the connected admins. For each admin, you have his connection date and his expiration date. You can also check the `Profile` and the `Rights` of the connected users.\n\nIf we check the profile and the rights of the previously logged user (from Keycloak in the previous part) we can retrieve the following information :\n\n```json\n{\n \"sub\": \"4c8cd101-ca28-4611-80b9-efa504ac51fd\",\n \"upn\": \"admin\",\n \"email_verified\": false,\n \"address\": {},\n \"groups\": [\n \"create-realm\",\n \"default-roles-master\",\n \"offline_access\",\n \"admin\",\n \"uma_authorization\"\n ],\n \"preferred_username\": \"admin\"\n}\n```\n\nand his default rights \n\n```sh\n[\n {\n \"tenant\": \"default:rw\",\n \"teams\": [\n \"default:rw\"\n ]\n }\n]\n```\n\nWe haven't create any specific groups in Keycloak or specify rights in Otoroshi for him. In this case, the use received the default Otoroshi rights at his connection. The user can navigate on the default Organization and Teams (which are two resources created by Otoroshi at the boot) and have the full access on its (`r`: Read, `w`: Write, `*`: read/write).\n\nIn the same way, you'll find all users connected to a private Otoroshi app when navigate on the @link:[`Private App View`](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private) or using the cog at the top of the page. \n\n### Configure the Keycloak module to force logged in users to be an Otoroshi admin with full access\n\nGo back to the Keycloak module in `Authentication configs` view. Turn on the `Supers admin only` button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.\n\nOnce connected, click on the cog button, and check that you have access to the full features of Otoroshi (like Admin user sessions). Now, your rights should be : \n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n]\n```\n\n### Merge Id token content on user profile\n\nGo back to the Keycloak module in `Authentication configs` view. Turn on the `Read profile` from token button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.\n\nOnce connected, your profile should be contains all Keycloak id token : \n```json\n{\n \"exp\": 1634286674,\n \"iat\": 1634286614,\n \"auth_time\": 1634286614,\n \"jti\": \"eb368578-e886-4caa-a51b-c1d04973c80e\",\n \"iss\": \"http://localhost:8080/auth/realms/master\",\n \"aud\": [\n \"master-realm\",\n \"account\"\n ],\n \"sub\": \"4c8cd101-ca28-4611-80b9-efa504ac51fd\",\n \"typ\": \"Bearer\",\n \"azp\": \"keycloak-otoroshi-backoffice\",\n \"session_state\": \"e44fe471-aa3b-477d-b792-4f7b4caea220\",\n \"acr\": \"1\",\n \"allowed-origins\": [\n \"http://otoroshi.oto.tools:8080\"\n ],\n \"realm_access\": {\n \"roles\": [\n \"create-realm\",\n \"default-roles-master\",\n \"offline_access\",\n \"admin\",\n \"uma_authorization\"\n ]\n },\n \"resource_access\": {\n \"master-realm\": {\n \"roles\": [\n \"view-identity-providers\",\n \"view-realm\",\n \"manage-identity-providers\",\n \"impersonation\",\n \"create-client\",\n \"manage-users\",\n \"query-realms\",\n \"view-authorization\",\n \"query-clients\",\n \"query-users\",\n \"manage-events\",\n \"manage-realm\",\n \"view-events\",\n \"view-users\",\n \"view-clients\",\n \"manage-authorization\",\n \"manage-clients\",\n \"query-groups\"\n ]\n },\n \"account\": {\n \"roles\": [\n \"manage-account\",\n \"manage-account-links\",\n \"view-profile\"\n ]\n }\n }\n ...\n}\n```\n\n### Manage the Otoroshi user rights from keycloak\n\nOne powerful feature supports by Otoroshi, is to use the Keycloak groups attributes to set a list of rights for a Otoroshi user.\n\nIn the Keycloak module, you have a field, named `Otoroshi rights field name` with `otoroshi_rights` as default value. This field is used by Otoroshi to retrieve information from the Id token groups.\n\nLet's create a group in Keycloak, and set our default Admin user inside.\nIn Keycloak admin console :\n\n1. Navigate to the groups view, using the keycloak sidebar\n2. Create a new group with `my-group` as `Name`\n3. Then, on the `Attributes` tab, create an attribute with `otoroshi_rights` as `Key` and the following json array as `Value`\n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```\n\nWith this configuration, the user have a full access on all Otoroshi resources (my-future-team is not created in Otoroshi but it's not a problem, Otoroshi can handle it and use this rights only when the team will be present)\n\nClick on the **Add** button and **save** the group. The last step is to assign our user to this group. Jump to `Users` view using the sidebar, click on **View all users**, edit the user and his group membership using the `Groups` tab (use **join** button the assign user in `my-group`).\n\nThe next step is to add a mapper in the Keycloak client. By default, Keycloak doesn't expose any users information (like group membership or users attribute). We need to ask to Keycloak to expose the user attribute `otoroshi_rights` set previously on group.\n\nNavigate to the `Keycloak-otoroshi-backoffice` client, and jump to `Mappers` tab. Create a new mapper with the following values: \n\n* Name: `otoroshi_rights`\n* Mapper Type: `User Attribute`\n* User Attribute: `otoroshi_rights`\n* Token Claim Name: `otoroshi_rights`\n* Claim JSON Type: `JSON`\n* Multivalued: `√`\n* Aggregate attribute values: `√`\n\nGo back to the Authentication Keycloak module inside Otoroshi UI, and turn off **Super admins only**. **Save** the configuration.\n\nOnce done, try again the connection to Otoroshi using Keycloak third-party server.\nNow, your rights should be : \n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```\n\n### Secure an app with Keycloak authentication\n\nThe only change to apply on the previous authentication module is on the callback URL. When you want secure a Otoroshi service, and transform it on `Private App`, you need to set the `Callback URL` at `http://privateapps.oto.tools:8080/privateapps/generic/callback`. This configuration will redirect users to the backend service after they have successfully logged in.\n\n1. Go back to the authentication module\n2. Jump to the `Callback URL` field\n3. Paste this value `http://privateapps.oto.tools:8080/privateapps/generic/callback`\n4. Save your configuration\n5. Navigate to `http://myservice.oto.tools:8080`.\n6. You should redirect to the keycloak login page.\n7. Once logged in, you can check the content of the private app session created.\n\nThe rights should be : \n\n```json\n[\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\",\n \"my-future-team:rw\"\n ]\n }\n]\n```"},{"name":"secure-app-with-ldap.md","id":"/how-to-s/secure-app-with-ldap.md","url":"/how-to-s/secure-app-with-ldap.html","title":"Secure an app and/or your Otoroshi UI with LDAP","content":"# Secure an app and/or your Otoroshi UI with LDAP\n\n### Before you start\n\n@@include[fetch-and-start.md](../includes/fetch-and-start.md) { #init }\n\n#### Running an simple OpenLDAP server \n\nRun OpenLDAP docker image : \n```sh\ndocker run \\\n -p 389:389 \\\n -p 636:636 \\\n --env LDAP_ORGANISATION=\"Otoroshi company\" \\\n --env LDAP_DOMAIN=\"otoroshi.tools\" \\\n --env LDAP_ADMIN_PASSWORD=\"otoroshi\" \\\n --env LDAP_READONLY_USER=\"false\" \\\n --env LDAP_TLS\"false\" \\\n --env LDAP_TLS_ENFORCE\"false\" \\\n --name my-openldap-container \\\n --detach osixia/openldap:1.5.0\n```\n\nLet's make the first search in our LDAP container :\n\n```sh\ndocker exec my-openldap-container ldapsearch -x -H ldap://localhost -b dc=otoroshi,dc=tools -D \"cn=admin,dc=otoroshi,dc=tools\" -w otoroshi\n```\n\nThis should output :\n```sh\n# extended LDIF\n ...\n# otoroshi.tools\ndn: dc=otoroshi,dc=tools\nobjectClass: top\nobjectClass: dcObject\nobjectClass: organization\no: Otoroshi company\ndc: otoroshi\n\n# search result\nsearch: 2\nresult: 0 Success\n...\n```\n\nNow you can seed the open LDAP server with a few users. \n\nJoin your LDAP container.\n\n```sh\ndocker exec -it my-openldap-container \"/bin/bash\"\n```\n\nThe command `ldapadd` needs of a file to run.\n\nLaunch this command to create a `bootstrap.ldif` with one organization, one singers group with Johnny user and a last group with Einstein as scientist.\n\n```sh\necho -e \"\ndn: ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: organizationalUnit\nou: People\n\ndn: ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: organizationalUnit\nou: Role\n\ndn: uid=johnny,ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: johnny\ncn: Johnny\nsn: Brown\nmail: johnny@otoroshi.tools\npostalCode: 88442\nuserPassword: password\n\ndn: uid=einstein,ou=People,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: einstein\ncn: Einstein\nsn: Wilson\nmail: einstein@otoroshi.tools\npostalCode: 88443\nuserPassword: password\n\ndn: cn=singers,ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: groupOfNames\ncn: singers\nmember: uid=johnny,ou=People,dc=otoroshi,dc=tools\n\ndn: cn=scientists,ou=Role,dc=otoroshi,dc=tools\nobjectclass: top\nobjectclass: groupOfNames\ncn: scientists\nmember: uid=einstein,ou=People,dc=otoroshi,dc=tools\n\" > bootstrap.ldif\n\nldapadd -x -w otoroshi -D \"cn=admin,dc=otoroshi,dc=tools\" -f bootstrap.ldif -v\n```\n\n### Create an Authentication configuration\n\n- Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n- Click on the cog icon on the top right\n- Then `Authentication configs` button\n- And add a new configuration when clicking on the `Add item` button\n- Select the `Ldap auth. provider` in the type selector field\n- Set a basic name and description\n- Then set `ldap://localhost:389` as `LDAP Server URL`and `dc=otoroshi,dc=tools` as `Search Base`\n- Create a group filter (in the next part, we'll change this filter to spread users in different groups with given rights) with \n - objectClass=groupOfNames as `Group filter` \n - All as `Tenant`\n - All as `Team`\n - Read/Write as `Rights`\n- Set the search filter as `(uid=${username})`\n- Set `cn=admin,dc=otoroshi,dc=tools` as `Admin username`\n- Set `otoroshi` as `Admin password`\n- At the bottom of the page, disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n\n At this point, your configuration should be similar to :\n \n\n\n\n> Dont' forget to save on the bottom page your configuration before to quit the page.\n\n- Test the connection when clicking on `Test admin connection` button. This should display a `It works!` message\n\n- Finally, test the user connection button and set `johnny/password` or `einstein/password` as credentials. This should display a `It works!` message\n\n> Dont' forget to save on the bottom page your configuration before to quit the page.\n\n\n### Connect to Otoroshi with LDAP authentication\n\nTo secure Otoroshi with your LDAP configuration, we have to register an **Authentication configuration** as a BackOffice Auth. configuration.\n\n- Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n- Scroll to the **BackOffice auth. settings**\n- Select your last Authentication configuration (created in the previous section)\n- Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n- Disconnect from your instance\n- Then click on the **Login using third-party** button (or navigate to @link:[http://otoroshi.oto.tools:8080/backoffice/auth0/login](http://otoroshi.oto.tools:8080/backoffice/auth0/login) { open=new })\n- Set `johnny/password` or `einstein/password` as credentials\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n\n#### Secure an app with LDAP authentication\n\nOnce the configuration is done, you can secure any of Otoroshi services. \n\n- Navigate to any created service\n- Jump to the `URL Patterns` section\n- Enable your service as `Public UI`\n- Then scroll to `Authentication` section\n- Enable `Enforce user authentication`\n- Select your Authentication config inside the list\n- Enable `Strict mode`\n- Don't forget to save your configuration\n\n\n\n\nNow you can try to call your defined service and see the login module appears.\n\n#### Manage LDAP users rights on Otoroshi\n\nFor each LDAP groups, you can affect a list of rights : \n\n- on an `Organization` : only resources of an organization\n- on a `Team` : only resources belonging to this team\n- and a level of rights : `Read`, `Write` or `Read/Write`\n\n\nStart by navigate to your authentication configuration (created in @ref:[previous](#create-an-authentication-configuration) step).\n\nThen, replace the values of the `Mapping group filter` field to match LDAP groups with Otoroshi rights.\n\n\n\n\nWith this configuration, Einstein is an administrator of Otoroshi with full rights (read / write) on all organizations.\n\nConversely, Johnny can't see any configuration pages (like the danger zone) because he has only the read rights on Otoroshi.\n\nYou can easily test this behaviour by @ref:[testing](#testing-your-configuration) with both credentials.\n\n\n#### Advanced usage of LDAP Authentication\n\nIn the previous section, we have define rights for each LDAP groups. But in some case, we want to have a finer granularity like set rights for a specific user. The last 4 fields of the authentication form cover this. \n\nLet's start by adding few properties for each connected users with `Extra metadata`.\n\n```json\n// Add this configuration in extra metadata part\n{\n \"provider\": \"OpenLDAP\"\n}\n```\n\nThe next field `Data override` is merged with extra metadata when a user connects to a `private app` or to the UI (inside Otoroshi, private app is a service secure by any authentication module). The `Email field name` is configured to match with the `mail` field from LDAP user data.\n\n```json \n{\n \"johnny@otoroshi.tools\": {\n \"stage_name\": \"Jean-Philippe Smet\"\n }\n}\n```\n\nIf you try to connect to an app with this configuration, the user result profile should be :\n\n```json\n{\n ...,\n \"metadata\": {\n \"lastname\": \"Hallyday\",\n \"stage_name\": \"Jean-Philippe Smet\"\n }\n}\n```\n\nLet's try to increase the Johnny rights with the `Additional rights group`.\n\nThis field supports the creation of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.\n\n```json\n// increase_johnny_rights is a virtual group which adds full access rights at johnny \n{\n \"increase_johnny_rights\": {\n \"rights\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ],\n \"users\": [\n \"johnny@otoroshi.tools\"\n ]\n }\n}\n```\n\nThe last field `Rights override` is useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights. \n\nTo resume, when Johnny connects to Otoroshi, he receives the rights to only read the default Organization (from **Mapping group filter**), then he is promote to administrator role (from **Additional rights group**) and finally his rights are reset with the last field **Rights override** to the read rights.\n\n```json \n{\n \"johnny@otoroshi.tools\": [\n {\n \"tenant\": \"*:r\",\n \"teams\": [\n \"*:r\"\n ]\n }\n ]\n}\n```\n\n\n\n\n\n\n\n\n"},{"name":"secure-the-communication-between-a-backend-app-and-otoroshi.md","id":"/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.md","url":"/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.html","title":"Secure the communication between a backend app and Otoroshi","content":"# Secure the communication between a backend app and Otoroshi\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n1. Navigate to http://otoroshi.oto.tools:8080/bo/services and create a new service\n2. Jump to `Service exposition settings` and add http://myservice.oto.tools as `Exposed domain`\n3. Jump to `Service targets` and add http://localhost:8081/ as `Target 1`\n4. Jump to the `URL Patterns` section\n5. Enable your service as `Public UI`\n6. Don't forget to save your service\n\nWe need of a simple service which handle the exchange protocol. For this tutorial, we'll use the following application, developed in NodeJS, which supports both versions of the exchange protocol.\n\nClone this @link:[repository](https://github.com/MAIF/otoroshi/blob/master/demos/challenge) and run the installation of the dependencies.\n\n```sh\ngit clone 'git@github.com:MAIF/otoroshi.git' --depth=1\ncd ./otoroshi/demos/challenge\nnpm install\nPORT=8081 node server.js\n```\n\nThe last command should return : \n\n```sh\nchallenge-verifier listening on http://0.0.0.0:8081\n```\n\nThis project runs an express client with one middleware. The middleware handles each request, and check if the header `State token header` is present in headers. By default, the incoming expected header is `Otoroshi-State` by the application and `Otoroshi-State-Resp` header in the headers of the return request. \n\nTry to call your service via http://myservice.oto.tools:8080/. This should return a successful response with all headers received by the backend app. \n\nNow try to disable the middleware in the nodejs file by commenting the following line. \n\n```js\n// app.use(OtoroshiMiddleware());\n```\n\nTry to call again your service. This time, Otoroshi breaks the return response from your backend service, and returns.\n\n```sh\nDownstream microservice does not seems to be secured. Cancelling request !\n```"},{"name":"secure-with-apikey.md","id":"/how-to-s/secure-with-apikey.md","url":"/how-to-s/secure-with-apikey.html","title":"Secure an api with api keys","content":"# Secure an api with api keys\n\n### Before you start\n\n@@include[fetch-and-start.md](../includes/fetch-and-start.md) { #init }\n\n### Create a simple service \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/services](http://otoroshi.oto.tools:8080/bo/dashboard/services) { open=new } and click on the `create new service` button\n2. Jump to `Service exposition settings` and add `http://myservice.oto.tools` as `Exposed domain`\n3. Jump to `Service targets` and add `https://mirror.otoroshi.io` as `Target 1`\n4. Jump to the `URL Patterns` section\n5. Enable your service as `Public UI`\n6. Open a new tab and navigate to @link:[http://myservice.oto.tools:8080](http://myservice.oto.tools:8080/) { open=new }\n\nWith this configuration, all routes are public, wihtout any authentication needed.\n\n### Secure routes with api key\n\nWith the previous configuration, all routes are public. In our case, we want to secure all routes prefix with `/api`.\n\nLet's return to the `URL Patterns` section. \nClick on **Make service a private api**. This button automatically add `/api` as default in `Private patterns` array. (Note that the field supports regex like. In our case, `/api.*` covers all routes starting by `/api`).\n\nSave your app and navigate to @link:[http://myservice.oto.tools:8080/api/test](http://myservice.oto.tools:8080/api/test) { open=new } again. If the service is configured, you should have a `Service Not found error`, and a success call, in the case you navigate to any other routes which are not starting by `/api/*` like @link:[http://myservice.oto.tools:8080/test/bar](http://myservice.oto.tools:8080/test/bar) { open=new }\n\nThe expected error on the `/api/test`, throws by the URL Patterns, indicate to the client that an api key is required to access to this part of the backend service.\n\n### Generate an api key to request secure services\n\nNavigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/apikeys/add](http://otoroshi.oto.tools:8080/bo/dashboard/apikeys/add) { open=new } or when clicking on the **Add apikey** button on the sidebar.\n\nThe only required fields of an Otoroshi api key are : \n\n* `ApiKey id`\n* `ApiKey Secret`\n* `ApiKey Name`\n\nThese fields are automatically generated by Otoroshi. However, you can override these values and indicate an additional description.\n\nTo simplify the rest of the tutorial, set the values:\n\n* `my-first-api-key-id` as `ApiKey Id`\n* `my-first-api-key-secret` as `ApiKey Secret`\n\nClick on **Create and stay on this ApiKey** button at the bottom of the page.\n\nNow you created the key, it's time to call our previous generated service with it.\n\nOtoroshi supports two methods to achieve that. \nOnce by passing Otoroshi api key in two headers : `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` (these headers names can be override on each service).\nAnd the second by passing Otoroshi api key in the authentication Header (basically the `Authorization` header) as a basic encoded value.\n\nLet's ahead and call our service :\n\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nAnd with the second method :\n\n```sh\ncurl -X GET \\\n -H 'Authorization: Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\n> Tips : To easily fill your headers, you can jump to the `Call examples` section in each api key view. In this section the header names are the default values and the service url is not set. You have to adapt these lines to your case. \n\n### Override defaults headers names for a service\n\nIn some case, we want to change the defaults headers names (and it's a quite good idea).\n\nLet's start by navigating to the `Api keys Constraints` section from the edit page of our sercice.\n\nThe first values to change are the headers names used to read the api key from client. Start by set :\n\n* `api-key-header-id` as `Custom client id header name`\n* `api-key-header-secret` as `Custom client secret header name`\n\nSave the service, and call the service again.\n\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nThis should output an error because Otoroshi are expecting the api keys in other headers.\n\n```json\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nCall one again the service but with the changed headers names.\n\n```sh\ncurl -X GET \\\n -H 'api-key-header-id: my-first-api-key-id' \\\n -H 'api-key-header-secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nWith this configuration, all others default services will accept the api keys with the `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers, while our service, will accept the `api-key-header-id` and `api-key-header-secret` headers.\n\n### Accept only api keys with expected values\n\nBy default, a secure service only accepts requests with api key. But all generated api keys are eligible to call our service and in some case, we want authorize only a couple of api keys.\n\nOne feature of Otoroshi is to restrict the list of accepted api keys by giving a list of `metadata` or/and `tags`. Each api key has a list of `tags` and `metadata`, which can be used by Otoroshi to forward or not a call with an api key. All api key metadata/tags can be forward to your service (see `Otoroshi exchange protocol` section of a service to get more information about `Send info. token`).\n\nLet's starting by accept only the api keys which come with the tag of `otoroshi` as value.\n\nJump to the last part of the `Api Keys Constraints` section, call `Routing constraints` (these constraints are used to forward a call to a service, only if all constraints are validated).\n\nIn our first case, set `otoroshi` in `One Tag in` array and save the service.\nThen call our service with :\n```sh\ncurl -X GET \\\n -H 'Otoroshi-Client-Id: my-first-api-key-id' \\\n -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \\\n 'http://myservice.oto.tools:8080/api/test' --include\n```\n\nThis should output :\n```json\n// Error reason : Our api key doesn't contains the expected tag.\n{\n \"Otoroshi-Error\": \"Bad API key\"\n}\n```\n\nNavigate to the edit page of our api key, and jump to the `Metadata and tags` section.\nIn this section, add `otoroshi` in `Tags` array, then save the api key. Call once again your call and you will normally get a successful response of our backend service.\n\nIn this example, we have restricted our service to be callable only with keys that have `otoroshi` as a tag.\n\nBut Otoroshi provides others behaviours. For each behaviour, *Api key used should*:\n\n* `All Tags in` : have all of the following tags\n* `No Tags in` : not have one of the following tags\n* `One Tag in` : have at least one of the following tags\n\n---\n\n* `All Meta. in` : have all of the following metadata entries\n* `No Meta. in` : not have one of the following metadata entries\n* `One Meta. in` : have at least one of the following metadata entries\n \n----\n\n* `One Meta key in` : have at least one of the following key in metadata\n* `All Meta key in` : have all of the following keys in metadata\n* `No Meta key in` : not have one of the following keys in metadata"},{"name":"secure-with-oauth1-client.md","id":"/how-to-s/secure-with-oauth1-client.md","url":"/how-to-s/secure-with-oauth1-client.html","title":"Secure an app with OAuth1 client flow","content":"# Secure an app with OAuth1 client flow\n\n### Before you start\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\n### Running an simple OAuth 1 server\n\nIn this tutorial, we'll instanciate a oauth 1 server with docker. If you alredy have the necessary, skip this section @ref:[to](#create-an-oauth-1-provider-module).\n\nLet's start by running the server\n\n```sh\ndocker run -d --name oauth1-server --rm \\\n -p 5000:5000 \\\n -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \\\n -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \\\n -e OAUTH1_REDIRECT_URI=http://otoroshi.oto.tools:8080/backoffice/auth0/callback \\\n ghcr.io/beryju/oauth1-test-server\n```\n\nWe created a oauth 1 server which accepts `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Redirect URI`. This URL is used by Otoroshi to retrieve a token and a profile at the end of an authentication process.\n\nAfter this command, the container logs should output :\n```sh \n127.0.0.1 - - [14/Oct/2021 12:10:49] \"HEAD /api/health HTTP/1.1\" 200 -\n```\n\n### Create an OAuth 1 provider module\n\n1. Go ahead, and navigate to @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new }\n1. Click on the cog icon on the top right\n1. Then **Authentication configs** button\n1. And add a new configuration when clicking on the **Add item** button\n2. Select the `Oauth1 provider` in the type selector field\n3. Set a basic name and description like `oauth1-provider`\n4. Set `2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET` as `Consumer key`\n5. Set `wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp` as `Consumer secret`\n6. Set `http://localhost:5000/oauth/request_token` as `Request Token URL`\n7. Set `http://localhost:5000/oauth/authorize` as `Authorize URL`\n8. Set `http://localhost:oauth/access_token` as `Access token URL`\n9. Set `http://localhost:5000/api/me` as `Profile URL`\n10. Set `http://otoroshi.oto.tools:8080/backoffice/auth0/callback` as `Callback URL`\n11. At the bottom of the page, disable the **secure** button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n At this point, your configuration should be similar to :\n\n\n\n\nWith this configuration, the connected user will receive default access on teams and organizations. If you want to change the access rights for a specific user, you can achieve it with the `Rights override` field and a configuration like :\n\n```json\n{\n \"foo@example.com\": [\n {\n \"tenant\": \"*:rw\",\n \"teams\": [\n \"*:rw\"\n ]\n }\n ]\n}\n```\n\nSave your configuration at the bottom of the page, then navigate to the `danger zone` to use your module as a third-party connection to the Otoroshi UI.\n\n### Connect to Otoroshi with OAuth1 authentication\n\nTo secure Otoroshi with your OAuth1 configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.\n\n1. Navigate to the **danger zone** (when clicking on the cog on the top right and selecting Danger zone)\n1. Scroll to the **BackOffice auth. settings**\n1. Select your last Authentication configuration (created in the previous section)\n1. Save the global configuration with the button on the top right\n\n### Testing your configuration\n\n1. Disconnect from your instance\n1. Then click on the **Login using third-party** button (or navigate to http://otoroshi.oto.tools:8080)\n2. Click on **Login using Third-party** button\n3. If all is configured, Otoroshi will redirect you to the oauth 1 server login page\n4. Set `example-user` as user and trust the user by clicking on `yes` button.\n5. Good work! You're connected to Otoroshi with an OAuth1 module.\n\n> A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.\n\n### Secure an app with OAuth 1 authentication\n\nWith the previous configuration, you can secure any of Otoroshi services with it. \n\nThe first step is to apply a little change on the previous configuration. \n\n1. Navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs](http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs) { open=new }.\n2. Create a new auth module configuration with the same values.\n3. Replace the `Callback URL` field to `http://privateapps.oto.tools:8080/privateapps/generic/callback` (we changed this value because the redirection of a logged user by a third-party server is cover by an other route by Otoroshi).\n4. Disable the `secure` button (because we're using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)\n\n> Note : an Otoroshi service is called a private app when it is protected by an authentication module.\n\nOur example server supports only one redirect URI. We need to kill it, and to create a new container with `http://otoroshi.oto.tools:8080/privateapps/generic/callback` as `OAUTH1_REDIRECT_URI`\n\n```sh\ndocker rm -f oauth1-server\ndocker run -d --name oauth1-server --rm \\\n -p 5000:5000 \\\n -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \\\n -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \\\n -e OAUTH1_REDIRECT_URI=http://privateapps.oto.tools:8080/privateapps/generic/callback \\\n ghcr.io/beryju/oauth1-test-server\n```\n\nOnce the authentication module and the new container created, we can define the authentication module on the service.\n\n1. Navigate to any created service\n2. Scroll to `Authentication` section\n3. Enable `Enforce user authentication`\n4. Select your Authentication config inside the list\n5. Enable `Strict mode`\n6. Don't forget to save your configuration.\n\nNow you can try to call your defined service and see the login module appears.\n\n> \n\nThe allow access to the user.\n\n> \n\nIf you had any errors, make sure of :\n\n* check if you are on http or https, and if the **secure cookie option** is enabled or not on the authentication module\n* check if your OAuth1 server has the REDIRECT_URI set on **privateapps/...**\n* Make sure your server supports POST or GET OAuth1 flow set on authentication module\n\nOnce the configuration is working, you can check, when connecting with an Otoroshi admin user, the `Private App session` created (use the cog at the top right of the page, and select `Priv. app sesssions`, or navigate to @link:[http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private](http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private) { open=new }).\n\nOne interesing feature is to check the profile of the connected user. In our case, when clicking on the `Profile` button of the right user, we should have : \n\n```json\n{\n \"email\": \"foo@example.com\",\n \"id\": 1,\n \"name\": \"test name\",\n \"screen_name\": \"example-user\"\n}\n```"},{"name":"secure-with-oauth2-client-credentials.md","id":"/how-to-s/secure-with-oauth2-client-credentials.md","url":"/how-to-s/secure-with-oauth2-client-credentials.html","title":"Secure an app with OAuth2 client_credential flow","content":"# Secure an app with OAuth2 client_credential flow\n\nOtoroshi makes it easy for your app to implement the [OAuth2 Client Credentials Flow](https://auth0.com/docs/authorization/flows/client-credentials-flow). Following successful authentication, the calling application will have access to an Access Token, which can be used to call your protected APIs.\n\n## Deployed the Client Credential Service\n\nThe Client Credential Service must be enabled as a global plugin on your Otoroshi instance. To achieve that, navigate to your otoroshi instance (in our case http://otoroshi.oto.tools:8080) on the danger zone (`top right cog icon / Danger zone` or at [/bo/dashboard/dangerzone](http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone)).\n\nTo enable a plugin in global on Otoroshi, you must add it in the `Global Plugins` section.\n\nOpen the `Global Plugin` section, click on `enabled` (if not already done), and search the plugin named `Client Credential Service` of type `Sink`.\n\nTo show and add the default configuration on this plugin, click on the `show config. panel` an on the `Inject default config.` button. This button is available on each plugin and it's useful when you want to inject the default configuration.\n\nWhen you click on the `show config. panel`, you have the documentation of the plugin and its default configuration.\n\nThe client credential plugin has by default 4 parameters : \n\n* `domain`: a regex used to exposed routes on each matching domain (`default`: *)\n* `expiration`: duration until the token expire (in ms) (`default`: 3600000)\n* `defaultKeyPair`: a key pair used to sign the jwt token. By default, Otoroshi is deployed with an otoroshi-jwt-signing that you can visualize on the jwt verifiers certificates (`default`: \"otoroshi-jwt-signing\")\n* `secure`: if enabled, Otoroshi will expose routes only in the https requests case (`default`: true)\n\nIn this tutorial, we will set the configuration as following : \n\n* `domain`: *.oto.tools\n* `expiration`: 3600000\n* `defaultKeyPair`: otoroshi-jwt-signing\n* `secure`: false\n\nNow that the plugin is running, third routes are exposed on each matching domain of the regex.\n\n* `GET /.well-known/otoroshi/oauth/jwks.json` : retrieve all public keys presents in Otoroshi\n* `POST /.well-known/otoroshi/oauth/token/introspect` : validate and decode the token \n* `POST /.well-known/otoroshi/oauth/token` : generate a token with the fields provided\n\nOnce the global configuration saved, we can deployed a simple service to test it.\n\nLet's navigate to the services page, and create a new service with : \n\n1. `http://foo.oto.tools:8080` as `Exposed domain` in `Service exposition settings` section\n2. `https://mirror.otoroshi.io` as `Target 1` in `Service targets` section\n3. `/.*` as `Private patterns` in `URL Patterns` section (and remove all public patterns)\n\nIn `Api Keys Constraints`, disabled `From basic auth.`, `Allow client id only usage` and `From custom headers` button then saved the service.\n\nLet's make a first call, to check if the jwks are already exposed :\n\n```sh\ncurl 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/jwks.json'\n```\n\nThis should output a list of public keys : \n```sh\n{\n \"keys\": [\n {\n \"kty\": \"RSA\",\n \"e\": \"AQAB\",\n \"kid\": \"otoroshi-intermediate-ca\",\n ...\n }\n ...\n ]\n}\n``` \n\nLet's make a call on a route of this service. \n\n```sh\ncurl 'http://foo.oto.tools:8080/'\n```\n\nThis should output the expected error: \n```json\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nThe first step is to generate an api key. Navigate to the api keys page, and create an item with the following values (it will be more easy to use them in the next step) :\n\n* `my-id` as `ApiKey Id`\n* `my-secret` as `ApiKey Secret`\n\nThe next step is to ask a token by calling the exposed route `/.well-known/otoroshi/oauth/jwks.json`. The required fields are the grand type, the client and the client secret corresponding to our generated api key.\n\n```sh\ncurl -X POST 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/token' \\\n -H \"Content-Type: application/json\" \\\n -d '{\"grant_type\":\"client_credentials\", \"client_id\":\"my-id\", \"client_secret\":\"my-secret\"}'\n```\n\nWe have omit a parameter of the body which is named `scope`. This field can be used to set a bunch of scope on the generated access token.\n\nThe last command should output : \n\n```sh\n{\n \"access_token\": \"generated-token-xxxxx\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600\n}\n```\n\nOnce generate, we can call our api again : \n```sh\ncurl 'http://foo.oto.tools:8080/' \\\n -H \"Authorization: Bearer generated-token-xxxxx\"\n```\n\nThis should output a list of headers with a field named `Authorization` containing the previous access token.\n\n\n## Other possible configuration\n\nBy default, Otoroshi generate the access token with the specified key pair in the configuration. But, in some case, you want a specific key pair by client_id/client_secret.\nYou can achieve it when setting a `jwt-sign-keypair` metadata on your desired api key with the id of the key pair as value. \n"},{"name":"setup-otoroshi-cluster.md","id":"/how-to-s/setup-otoroshi-cluster.md","url":"/how-to-s/setup-otoroshi-cluster.html","title":"Setup an Otoroshi cluster","content":"# Setup an Otoroshi cluster\n\nIn this tutorial, we will deploy an Otoroshi cluster with one leader and 2 workers. We will add a load balancer in front of the workers and validate the installation by adding a header on the requests.\n\nLet's start by downloading the latest jar of Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nThen create an instance of Otoroshi and indicates with the `otoroshi.cluster.mode` environment variable that it will be the leader.\n\n```sh\njava -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar\n```\n\nOnce created, we have to create the two workers. For both workers, we have to set the ip and the url of their leader in the `otoroshi.cluster.leader.urls` environment variable.\n\nThe first worker will listen on the `:8082/:8092` ports\n```sh\njava \\\n -Dotoroshi.cluster.worker.name=worker-1 \\\n -Dhttp.port=8092 \\\n -Dhttps.port=9092 \\\n -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar\n```\n\nThe second worker will listen on the `:8083/:8093` ports\n```sh\njava \\\n -Dotoroshi.cluster.worker.name=worker-2 \\\n -Dhttp.port=8093 \\\n -Dhttps.port=9093 \\\n -Dotoroshi.cluster.mode=worker \\\n -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar\n```\n\nOnce launched, you can navigate to the @link:[cluster view](http://otoroshi.oto.tools:8091/bo/dashboard/cluster) { open=new }. If all is configured, you will see the leader, the 2 workers and a bunch of informations about each instance.\n\nTo complete our installation, we want to spread the incoming requests accross otoroshi worker instances. \n\nIn this tutorial, we will use haproxy has a TCP loadbalancer. If you don't have haproxy installed, you can use docker to run an haproxy instance as explained below.\n\nBut first, we need an haproxy configuration file named `haproxy.cfg` with the following content :\n\n```sh\nfrontend front_nodes_http\n bind *:8080\n mode tcp\n default_backend back_http_nodes\n timeout client 1m\n\nbackend back_http_nodes\n mode tcp\n balance roundrobin\n server node1 host.docker.internal:8092 # (1)\n server node2 host.docker.internal:8093 # (1)\n timeout connect 10s\n timeout server 1m\n```\n\nand run haproxy with this config file\n\nno docker\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #no_docker }\n\ndocker (on linux)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_linux }\n\ndocker (on macos)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_mac }\n\ndocker (on windows)\n: @@snip [run.sh](../snippets/cluster-run-ha.sh) { #docker_windows }\n\nThe last step is to create a service, add a rule to add, in the headers, a specific value to identify the worker used.\n\nCreate this service, exposed on `http://myapi.oto.tools:xxxx`, which will forward all requests to the mirror `https://mirror.otoroshi.io`.\n\n```sh\ncurl -X POST http://otoroshi-api.oto.tools:8091/api/services \\\n-H \"Content-type: application/json\" \\\n-u admin-api-apikey-id:admin-api-apikey-secret \\\n-d @- <<'EOF'\n{\n \"enforceSecureCommunication\": false,\n \"forceHttps\": false,\n \"_loc\": {\n \"tenant\": \"default\",\n \"teams\": [\n \"default\"\n ]\n },\n \"groupId\": \"default\",\n \"groups\": [\n \"default\"\n ],\n \"id\": \"myapi\",\n \"name\": \"myapi\",\n \"description\": \"myapi\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"api\",\n \"targetsLoadBalancing\": {\n \"type\": \"RoundRobin\"\n },\n \"targets\": [\n {\n \"host\": \"mirror.otoroshi.io\",\n \"scheme\": \"https\",\n \"weight\": 1,\n \"mtlsConfig\": {\n \"certs\": [],\n \"trustedCerts\": [],\n \"mtls\": false,\n \"loose\": false,\n \"trustAll\": false\n },\n \"tags\": [],\n \"metadata\": {},\n \"protocol\": \"HTTP\\/1.1\",\n \"predicate\": {\n \"type\": \"AlwaysMatch\"\n },\n \"ipAddress\": null\n }\n ],\n \"root\": \"\\/\",\n \"matchingRoot\": null,\n \"stripPath\": true,\n \"enabled\": true,\n \"publicPatterns\": [\n \"/.*\"\n ],\n \"kind\": \"ServiceDescriptor\",\n \"additionalHeaders\": {\n \"worker-name\": \"${config.otoroshi.cluster.worker.name}\"\n }\n}\nEOF\n```\n\nOnce created, call two times the service. If all is working, the header received by the backend service will have `worker-1` and `worker-2` as value.\n\n```sh\ncurl 'http://api.oto.tools:8080'\n## Response headers\n{\n ...\n \"worker-name\": \"worker-2\"\n ...\n}\n```\n\nThis should output `worker-1`, then `worker-2`, etc. Well done, your loadbalancing is working and your cluster is set up correctly.\n\n\n"},{"name":"tls-termination-using-own-certificates.md","id":"/how-to-s/tls-termination-using-own-certificates.md","url":"/how-to-s/tls-termination-using-own-certificates.html","title":"TLS termination using your own certificates","content":"# TLS termination using your own certificates\n\nThe goal of this tutorial is to expose a service via https using a certificate generated by openssl.\n\n@@include[initialize.md](../includes/initialize.md) { #initialize-otoroshi }\n\nTry to call the service.\n\n```sh\ncurl 'http://myservice.oto.tools:8080'\n```\n\nThis should output something like\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.opunmaif.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"x-forwarded-port\": \"443\",\n \"opun-proxied-host\": \"mirror.otoroshi.io\",\n \"otoroshi-request-id\": \"1463145856319359618\",\n \"otoroshi-proxied-host\": \"myservice.oto.tools:8080\",\n \"opun-gateway-request-id\": \"1463145856554240100\",\n \"x-forwarded-proto\": \"https\",\n },\n \"body\": \"\"\n}\n```\n\nLet's try to call the service in https.\n\n```sh\ncurl 'https://myservice.oto.tools:8443'\n```\n\nThis should output\n\n```sh\ncurl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myservice.oto.tools:8443\n```\n\nTo fix it, we have to generate a certificate and import it in Otoroshi to match the domain `myservice.oto.tools`.\n\n> If you already had a certificate you can skip the next set of commands and directly import your certificate in Otoroshi\n\nWe will use openssl to generate a private key and a self-signed certificate.\n\n```sh\nopenssl genrsa -out myservice.key 4096\n# remove pass phrase\nopenssl rsa -in myservice.key -out myservice.key\n# generate the certificate authority cert\nopenssl req -new -x509 -sha256 -days 730 -key myservice.key -out myservice.cer -subj \"/CN=myservice.oto.tools\"\n```\n\nCheck the content of the certificate \n\n```sh\nopenssl x509 -in myservice.cer -text\n```\n\nThis should contains something like\n\n```sh\nCertificate:\n Data:\n Version: 1 (0x0)\n Serial Number: 9572962808320067790 (0x84d9fef455f188ce)\n Signature Algorithm: sha256WithRSAEncryption\n Issuer: CN=myservice.oto.tools\n Validity\n Not Before: Nov 23 14:25:55 2021 GMT\n Not After : Nov 23 14:25:55 2022 GMT\n Subject: CN=myservice.oto.tools\n Subject Public Key Info:\n Public Key Algorithm: rsaEncryption\n Public-Key: (4096 bit)\n Modulus:\n...\n```\n\nOnce generated, go back to Otoroshi and navigate to the certificates management page (`top right cog icon / SSL/TLS certificates` or at @link:[`/bo/dashboard/certificates`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates)) and click on `Add item`.\n\nSet `myservice-certificate` as `name` and `description`.\n\nDrop the `myservice.cer` file or copy the content to the `Certificate full chain` field.\n\nDo the same action for the `myservice.key` file in the `Certificate private key` field.\n\nSet your passphrase password in the `private key password` field if you added one.\n\nLet's try the same call to the service.\n\n```sh\ncurl 'https://myservice.oto.tools:8443'\n```\n\nAn error should occurs due to the untrsuted received certificate server\n\n```sh\ncurl: (60) SSL certificate problem: self signed certificate\nMore details here: https://curl.haxx.se/docs/sslcerts.html\n\ncurl failed to verify the legitimacy of the server and therefore could not\nestablish a secure connection to it. To learn more about this situation and\nhow to fix it, please visit the web page mentioned above.\n```\n\nEnd this tutorial by trusting the certificate server \n\n```sh\ncurl 'https://myservice.oto.tools:8443' --cacert myservice.cer\n```\n\nThis should finally output\n\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/\",\n \"headers\": {\n \"host\": \"mirror.opunmaif.io\",\n \"accept\": \"*/*\",\n \"user-agent\": \"curl/7.64.1\",\n \"x-forwarded-port\": \"443\",\n \"opun-proxied-host\": \"mirror.otoroshi.io\",\n \"otoroshi-request-id\": \"1463158439730479893\",\n \"otoroshi-proxied-host\": \"myservice.oto.tools:8443\",\n \"opun-gateway-request-id\": \"1463158439558515871\",\n \"x-forwarded-proto\": \"https\",\n \"sozu-id\": \"01FN6MGKSYZNJYHEMP4R5PJ4Q5\"\n },\n \"body\": \"\"\n}\n```\n\n"},{"name":"tls-using-lets-encrypt.md","id":"/how-to-s/tls-using-lets-encrypt.md","url":"/how-to-s/tls-using-lets-encrypt.html","title":"TLS termination using Let's Encrypt","content":"# TLS termination using Let's Encrypt\n\nAs you know, Otoroshi is capable of doing TLS termination for your services. You can import your own certificates, generate certificates from scratch and you can also use the @link:[ACME protocol](https://datatracker.ietf.org/doc/html/rfc8555) to generate certificates. One of the most popular service offering ACME certificates creation is @link:[Let's Encrypt](https://letsencrypt.org/).\n\n@@@ warning\nIn order to make this tutorial work, your otoroshi instance MUST be accessible from the internet in order to be reachable by Let's Encrypt ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.\n@@@\n\n@@@ note\nthis tutorial can work with any ACME provider with the same rules. your otoroshi instance MUST be accessible by the ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.\n@@@\n\n## Setup let's encrypt on otoroshi\n\nGo on the danger zone page by clicking on the [`cog icon / Danger Zone`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates). Scroll to the `Let's Encrypt settings` section. Enable it, and specify the address of the ACME server (for production Let's Encrypt it's `acme://letsencrypt.org`, for testing, it's `acme://letsencrypt.org/staging`. Any ACME server address should work). You can also add one or more email addresses or contact urls that will be included in your Let's Encrypt account. You don't have to fill the `public/private key` inputs as they will be automatically generated on the first usage.\n\n## Creating let's encrypt certificate from FQDNs\n\nYou can go to the certificates page by clicking on the [`cog icon / SSL/TLS Certificates`](http://otoroshi.oto.tools:8080/bo/dashboard/certificates). Here, click on the `+ Let's Encrypt certificate` button. A popup will show up to ask you the FQDN that you want for you certificate. Once done, click on the `Create` button. A few moment later, you will be redirected on a brand new certificate generated by Let's encrypt. You can now enjoy accessing your service behind the FQDN with TLS.\n\n## Creating let's encrypt certificate from a service\n\nYou can go to any service page and enable the flag `Issue Let's Encrypt cert.`. Do not forget to save your service. A few moment later, the certificates will be available in the certificates page and you can will be able to enjoy accessing your service with TLS.\n"},{"name":"fetch-and-start.md","id":"/includes/fetch-and-start.md","url":"/includes/fetch-and-start.html","title":"","content":"\nIf you already have an up and running otoroshi instance, you can skip the following instructions\n\nLet's start by downloading the latest Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nthen you can run start Otoroshi :\n\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\nNow you can log into Otoroshi at @link:[http://otoroshi.oto.tools:8080](http://otoroshi.oto.tools:8080) { open=new } with `admin@otoroshi.io/password`\n"},{"name":"initialize.md","id":"/includes/initialize.md","url":"/includes/initialize.html","title":"","content":"\n\nIf you already have an up and running otoroshi instance, you can skip the following instructions\n\n\n@@@div { .instructions }\n\n
\nI want to follow the instructions to start an instance of Otorohi\n\n
\n\nLet's start by downloading the latest Otoroshi.\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n```\n\nthen you can run start Otoroshi :\n\n```sh\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n```\n\nNow you can log into Otoroshi at http://otoroshi.oto.tools:8080 with `admin@otoroshi.io/password`\n\nCreate a service, exposed on `http://myservice.oto.tools:8080`, which will forward all requests to the mirror `https://mirror.otoroshi.io`. Each call to this service will returned the body and the headers received by the mirror.\n\n```sh\ncurl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \\\n -d '{\"enforceSecureCommunication\": false, \"forceHttps\": false, \"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"name\":\"my-service\",\"description\":\"a service\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"myservice\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"\\/.*\"],\"privatePatterns\":[],\"kind\":\"ServiceDescriptor\"}' \\\n -H \"Content-type: application/json\" \\\n -u admin-api-apikey-id:admin-api-apikey-secret\n```\n\n\n@@@\n"},{"name":"index.md","id":"/index.md","url":"/index.html","title":"Otoroshi","content":"# Otoroshi\n\n**Otoroshi** is a layer of lightweight api management on top of a modern http reverse proxy written in Scala and developped by the MAIF OSS team that can handle all the calls to and between your microservices without service locator and let you change configuration dynamicaly at runtime.\n\n\n> *The Otoroshi is a large hairy monster that tends to lurk on the top of the torii gate in front of Shinto shrines. It's a hostile creature, but also said to be the guardian of the shrine and is said to leap down from the top of the gate to devour those who approach the shrine for only self-serving purposes.*\n\n@@@ div { .centered-img }\n[![build](https://github.com/MAIF/otoroshi/actions/workflows/server_build_and_test.yaml/badge.svg)](https://github.com/MAIF/otoroshi/actions/workflows/server_build_and_test.yaml) [![Join the chat at https://gitter.im/MAIF/otoroshi](https://badges.gitter.im/MAIF/otoroshi.svg)](https://gitter.im/MAIF/otoroshi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [ ![Download](https://img.shields.io/github/release/MAIF/otoroshi.svg) ](hhttps://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\n## Installation\n\nYou can download the latest build of Otoroshi as a @ref:[fat jar](./install/get-otoroshi.md#from-jar-file), as a @ref:[zip package](./install/get-otoroshi.md#from-zip) or as a @ref:[docker image](./install/get-otoroshi.md#from-docker).\n\nYou can install and run Otoroshi with this little bash snippet\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\njava -jar otoroshi.jar\n```\n\nor using docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi:1.5.11\n```\n\nnow open your browser to http://otoroshi.oto.tools:8080/, **log in with the credential generated in the logs** and explore by yourself, if you want better instructions, just go to the @ref:[Quick Start](./getting-started.md) or directly to the @ref:[installation instructions](./install/get-otoroshi.md)\n\n## Documentation\n\n* @ref:[About Otoroshi](./about.md)\n* @ref:[Architecture](./architecture.md)\n* @ref:[Features](./features.md)\n* @ref:[Getting started](./getting-started.md)\n* @ref:[Install Otoroshi](./install/index.md)\n* @ref:[Main entities](./entities/index.md)\n* @ref:[Detailed topics](./topics/index.md)\n* @ref:[How to's](./how-to-s/index.md)\n* @ref:[Plugins](./plugins/index.md)\n* @ref:[Admin REST API](./api.md)\n* @ref:[Deploy to production](./deploy/index.md)\n* @ref:[Developing Otoroshi](./dev.md)\n* @ref:[Otoroshi next](./next/index.md)\n\n## Discussion\n\nJoin the [Otoroshi](https://gitter.im/MAIF/otoroshi) channel on the [MAIF Gitter](https://gitter.im/MAIF) { open=new }\n\n## Sources\n\nThe sources of Otoroshi are available on @link:[Github](https://github.com/MAIF/otoroshi) { open=new }.\n\n## Logo\n\nYou can find the official Otoroshi logo @link:[on GitHub](https://github.com/MAIF/otoroshi/blob/master/resources/otoroshi-logo.png) { open=new }. The Otoroshi logo has been created by François Galioto ([@fgalioto](https://twitter.com/fgalioto))\n\n## Changelog\n\nEvery release, along with the migration instructions, is documented on the @link:[Github Releases](https://github.com/MAIF/otoroshi/releases) { open=new } page. A condensed version of the changelog is available on @link:[github](https://github.com/MAIF/otoroshi/blob/master/CHANGELOG.md) { open=new }\n\n## Patrons\n\nThe work on Otoroshi was funded by MAIF with the help of the community.\n\n## Licence\n\nOtoroshi is Open Source and available under the @link:[Apache 2 License](https://opensource.org/licenses/Apache-2.0) { open=new }\n\n@@@ index\n\n* [About Otoroshi](./about.md)\n* [Architecture](./architecture.md)\n* [Features](./features.md)\n* [Getting started](./getting-started.md)\n* [Install Otoroshi](./install/index.md)\n* [Main entities](./entities/index.md)\n* [Detailed topics](./topics/index.md)\n* [How to's](./how-to-s/index.md)\n* [Plugins](./plugins/index.md)\n* [Admin REST API](./api.md)\n* [Deploy to production](./deploy/index.md)\n* [Developing Otoroshi](./dev.md)\n* [Otoroshi next](./next/index.md)\n\n@@@\n\n"},{"name":"get-otoroshi.md","id":"/install/get-otoroshi.md","url":"/install/get-otoroshi.html","title":"Get Otoroshi","content":"# Get Otoroshi\n\nAll release can be bound on the releases page of the @link:[repository](https://github.com/MAIF/otoroshi/releases) { open=new }.\n\n## From zip\n\n```sh\n# Download the latest version\nwget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi-1.5.11.zip\nunzip ./otoroshi-1.5.11.zip\ncd otoroshi-1.5.11\n```\n\n## From jar file\n\n```sh\n# Download the latest version\nwget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar\n```\n\n## From Docker\n\n```sh\n# Download the latest version\ndocker pull maif/otoroshi:1.5.11-jdk11\n```\n\n## From Sources\n\nTo build Otoroshi from sources, just go to the @ref:[dev documentation](../dev.md)\n"},{"name":"index.md","id":"/install/index.md","url":"/install/index.html","title":"Install","content":"# Install\n\nIn this sections, you will find informations about how to install and run Otoroshi\n\n* @ref:[Get Otoroshi](./get-otoroshi.md)\n* @ref:[Setup Otoroshi](./setup-otoroshi.md)\n* @ref:[Run Otoroshi](./run-otoroshi.md)\n\n@@@ index\n\n* [Get Otoroshi](./get-otoroshi.md)\n* [Setup Otoroshi](./setup-otoroshi.md)\n* [Run Otoroshi](./run-otoroshi.md)\n\n@@@\n"},{"name":"run-otoroshi.md","id":"/install/run-otoroshi.md","url":"/install/run-otoroshi.html","title":"Run Otoroshi","content":"# Run Otoroshi\n\nNow you are ready to run Otoroshi. You can run the following command with some tweaks depending on the way you want to configure Otoroshi. If you want to pass a custom configuration file, use the `-Dconfig.file=/path/to/file.conf` flag in the following commands.\n\n## From .zip file\n\n```sh\ncd otoroshi-vx.x.x\n./bin/otoroshi\n```\n\n## From .jar file\n\nFor Java 11\n\n```sh\njava -jar otoroshi.jar\n```\n\nif you want to run the jar file for on a JDK above JDK11, you'll have to add the following flags\n\n```sh\njava \\\n --add-opens=java.base/javax.net.ssl=ALL-UNNAMED \\\n --add-opens=java.base/sun.net.www.protocol.file=ALL-UNNAMED \\\n --add-exports=java.base/sun.security.x509=ALL-UNNAMED \\\n --add-opens=java.base/sun.security.ssl=ALL-UNNAMED \\\n -Dlog4j2.formatMsgNoLookups=true \\\n -jar otoroshi.jar\n```\n\n## From docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi\n```\n\nYou can also pass useful args like :\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi -Dconfig.file=/usr/app/otoroshi/conf/otoroshi.conf -Dlogger.file=/usr/app/otoroshi/conf/otoroshi.xml\n```\n\nIf you want to provide your own config file, you can read @ref:[the documentation about config files](./setup-otoroshi.md).\n\nYou can also provide some ENV variable using the `--env` flag to customize your Otoroshi instance.\n\nThe list of possible env variables is available @ref:[here](./setup-otoroshi.md).\n\nYou can use a volume to provide configuration like :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd):/usr/app/otoroshi/conf\" maif/otoroshi\n```\n\nYou can also use a volume if you choose to use `filedb` datastore like :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd)/filedb:/usr/app/otoroshi/filedb\" maif/otoroshi -Dotoroshi.storage=file\n```\n\nYou can also use a volume if you choose to use exports files :\n\n```sh\ndocker run -p \"8080:8080\" -v \"$(pwd):/usr/app/otoroshi/imports\" maif/otoroshi -Dotoroshi.importFrom=/usr/app/otoroshi/imports/export.json\n```\n\n## Run examples\n\n```sh\n$ java \\\n -Xms2G \\\n -Xmx8G \\\n -Dhttp.port=8080 \\\n -Dotoroshi.importFrom=/home/user/otoroshi.json \\\n -Dconfig.file=/home/user/otoroshi.conf \\\n -jar ./otoroshi.jar\n\n[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[warn] otoroshi-env - Importing from: /home/user/otoroshi.json\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n```\n\nIf you choose to start Otoroshi without importing existing data, Otoroshi will create a new admin user and print the login details in the log. When you will log into the admin dashboard, Otoroshi will ask you to create another account to avoid security issues.\n\n```sh\n$ java \\\n -Xms2G \\\n -Xmx8G \\\n -Dhttp.port=8080 \\\n -jar otoroshi.jar\n\n[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores\n[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services\n[warn] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / HHUsiF2UC3OPdmg0lGngEv3RrbIwWV5W\n[info] play.api.Play - Application started (Prod)\n[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080\n```\n"},{"name":"setup-otoroshi.md","id":"/install/setup-otoroshi.md","url":"/install/setup-otoroshi.html","title":"Setup Otoroshi","content":"# Setup Otoroshi\n\nin this section we are going to configure otoroshi before running it for the first time\n\n## Setup the database\n\nRight now, Otoroshi supports multiple datastore. You can choose one datastore over another depending on your use case.\n\n@@@div { .plugin .platform } \n
Redis
\n\n
Recommended
\n\nThe **redis** datastore is quite nice when you want to easily deploy several Otoroshi instances.\n\n\n\n@link:[Documentation](https://redis.io/topics/quickstart)\n@@@\n\n@@@div { .plugin .platform } \n
In memory
\n\nThe **in-memory** datastore is kind of interesting. It can be used for testing purposes, but it is also a good candidate for production because of its fastness.\n\n\n\n@ref:[Start with](../getting-started.md)\n@@@\n\n@@@div { .plugin .platform } \n
Cassandra
\n\n
Clustering
\n\nExperimental support, should be used in cluster mode for leaders\n\n\n\n@link:[Documentation](https://cassandra.apache.org/doc/latest/cassandra/getting_started/installing.html)\n@@@\n\n@@@div { .plugin .platform } \n
Postgresql
\n\n
Clustering
\n\nOr any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)\n\n\n\n@link:[Documentation](https://www.postgresql.org/docs/10/tutorial-install.html)\n@@@\n\n@@@div { .plugin .platform } \n\n
FileDB
\n\nThe **filedb** datastore is pretty handy for testing purposes, but is not supposed to be used in production mode. \nNot suitable for production usage.\n\n\n\n@@@\n\n\n@@@ div { .centered-img }\n\n@@@\n\nthe first thing to setup is what kind of datastore you want to use with the `otoroshi.storage` setting\n\n```conf\notoroshi {\n storage = \"inmemory\" # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n storage = ${?APP_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n storage = ${?OTOROSHI_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg \n}\n```\n\ndepending on the value you chose, you will be able to configure your datastore with the following configuration\n\ninmemory\n: @@snip [inmemory.conf](../snippets/datastores/inmemory.conf) \n\nfile\n: @@snip [file.conf](../snippets/datastores/file.conf) \n\nhttp\n: @@snip [http.conf](../snippets/datastores/http.conf) \n\ns3\n: @@snip [s3.conf](../snippets/datastores/s3.conf) \n\nredis\n: @@snip [redis.conf](../snippets/datastores/redis.conf) \n\nredis with lettuce\n: @@snip [lettuce.conf](../snippets/datastores/lettuce.conf) \n\npostgresql\n: @@snip [pg.conf](../snippets/datastores/pg.conf) \n\ncassandra\n: @@snip [inmemory.conf](../snippets/datastores/cassandra.conf) \n\n## Setup your hosts before running\n\nBy default, Otoroshi starts with domain `oto.tools` that automatically targets `127.0.0.1` with no changes to your `/etc/hosts` file. Of course you can change the domain value, you have to add the values in your `/etc/hosts` file according to the setting you put in Otoroshi configuration or define the right ip address at the DNS provider level\n\n* `otoroshi.domain` => `mydomain.org`\n* `otoroshi.backoffice.subdomain` => `otoroshi`\n* `otoroshi.privateapps.subdomain` => `privateapps`\n* `otoroshi.adminapi.exposedSubdomain` => `otoroshi-api`\n* `otoroshi.adminapi.targetSubdomain` => `otoroshi-admin-internal-api`\n\nfor instance if you want to change the default domain and use something like `otoroshi.mydomain.org`, then start otoroshi like \n\n```sh\njava -Dotoroshi.domain=mydomain.org -jar otoroshi.jar\n```\n\n@@@ warning\nOtoroshi cannot be accessed using `http://127.0.0.1:8080` or `http://localhost:8080` because Otoroshi uses Otoroshi to serve it's own UI and API. When otoroshi starts with an empty database, it will create a service descriptor for that using `otoroshi.domain` and the settings listed on this page and in the here that serve Otoroshi API and UI on `http://otoroshi-api.${otoroshi.domain}` and `http://otoroshi.${otoroshi.domain}`.\nOnce the descriptor is saved in database, if you want to change `otoroshi.domain`, you'll have to edit the descriptor in the database or restart Otoroshi with an empty database.\n@@@\n\n@@@ warning\nif your otoroshi instance runs behind a reverse proxy (L4 / L7) or inside a docker container where exposed ports (that you will use to access otoroshi) are not the same that the ones configured in otoroshi (`http.port` and `https.port`), you'll have to configure otoroshi exposed port to avoid bad redirection URLs when using authentication modules and other otoroshi tools. To do that, just set the values of the exposed ports in `otoroshi.exposed-ports.http = $theExposedHttpPort` (OTOROSHI_EXPOSED_PORTS_HTTP) and `otoroshi.exposed-ports.https = $theExposedHttpsPort` (OTOROSHI_EXPOSED_PORTS_HTTPS)\n@@@\n\n## Setup your configuration file\n\nThere is a lot of things you can configure in Otoroshi. By default, Otoroshi provides a configuration that should be enough for testing purpose. But you'll likely need to update this configuration when you'll need to move into production.\n\nIn this page, any configuration property can be set at runtime using a `-D` flag when launching Otoroshi like \n\n```sh\njava -Dhttp.port=8080 -jar otoroshi.jar\n```\n\nor\n\n```sh\n./bin/otoroshi -Dhttp.port=8080 \n```\n\nif you want to define your own config file and use it on an otoroshi instance, use the following flag\n\n```sh\njava -Dconfig.file=/path/to/otoroshi.conf -jar otoroshi.jar\n``` \n\n### Example of a custom. configuration file\n\n```conf\ninclude \"application.conf\"\n\nhttp.port = 8080\n\napp {\n storage = \"inmemory\"\n importFrom = \"./my-state.json\"\n env = \"prod\"\n domain = \"oto.tools\"\n rootScheme = \"http\"\n snowflake {\n seed = 0\n }\n events {\n maxSize = 1000\n }\n backoffice {\n subdomain = \"otoroshi\"\n session {\n exp = 86400000\n }\n }\n privateapps {\n subdomain = \"privateapps\"\n session {\n exp = 86400000\n }\n }\n adminapi {\n targetSubdomain = \"otoroshi-admin-internal-api\"\n exposedSubdomain = \"otoroshi-api\"\n defaultValues {\n backOfficeGroupId = \"admin-api-group\"\n backOfficeApiKeyClientId = \"admin-api-apikey-id\"\n backOfficeApiKeyClientSecret = \"admin-api-apikey-secret\"\n backOfficeServiceId = \"admin-api-service\"\n }\n }\n claim {\n sharedKey = \"mysecret\"\n }\n filedb {\n path = \"./filedb/state.ndjson\"\n }\n}\n\nplay.http {\n session {\n secure = false\n httpOnly = true\n maxAge = 2592000000\n domain = \".oto.tools\"\n cookieName = \"oto-sess\"\n }\n}\n```\n\n### Reference configuration\n\n@@snip [reference.conf](../snippets/reference.conf) \n\n### More config. options\n\nSee default configuration at\n\n* @link:[Base configuration](https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/base.conf) { open=new }\n* @link:[Application configuration](https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/application.conf) { open=new }\n\n## Configuration with env. variables\n\nEevery property in the configuration file can be overriden by an environment variable if it has env variable override written like `${?ENV_VARIABLE}`).\n\n## Reference configuration for env. variables\n\n@@snip [reference-env.conf](../snippets/reference-env.conf) \n"},{"name":"built-in-plugins.md","id":"/next/built-in-plugins.md","url":"/next/built-in-plugins.html","title":"Built-in plugins","content":"# Built-in plugins\n\nOtoroshi next provides some plugins out of the box. Here is the available plugins with their documentation and reference configuration\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AdditionalHeadersIn }\n\n## Additional headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AdditionalHeadersIn`\n\n### Description\n\nThis plugin adds headers in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AdditionalHeadersOut }\n\n## Additional headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AdditionalHeadersOut`\n\n### Description\n\nThis plugin adds headers in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AllowHttpMethods }\n\n## Allowed HTTP methods\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AllowHttpMethods`\n\n### Description\n\nThis plugin verifies the current request only uses allowed http methods\n\n\n\n### Default configuration\n\n```json\n{\n \"allowed\" : [ ],\n \"forbidden\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ApikeyCalls }\n\n## Apikeys\n\n### Defined on steps\n\n - `MatchRoute`\n - `ValidateAccess`\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ApikeyCalls`\n\n### Description\n\nThis plugin expects to find an apikey to allow the request to pass\n\n\n\n### Default configuration\n\n```json\n{\n \"extractors\" : {\n \"basic\" : {\n \"enabled\" : true,\n \"header_name\" : null,\n \"query_name\" : null\n },\n \"custom_headers\" : {\n \"enabled\" : true,\n \"client_id_header_name\" : null,\n \"client_secret_header_name\" : null\n },\n \"client_id\" : {\n \"enabled\" : true,\n \"header_name\" : null,\n \"query_name\" : null\n },\n \"jwt\" : {\n \"enabled\" : true,\n \"secret_signed\" : true,\n \"keypair_signed\" : true,\n \"include_request_attrs\" : false,\n \"max_jwt_lifespan_sec\" : null,\n \"header_name\" : null,\n \"query_name\" : null,\n \"cookie_name\" : null\n }\n },\n \"routing\" : {\n \"enabled\" : false\n },\n \"validate\" : true,\n \"pass_with_user\" : false,\n \"wipe_backend_request\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ApikeyQuotas }\n\n## Apikey quotas\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ApikeyQuotas`\n\n### Description\n\nIncrements quotas for the currents apikey. Useful when 'legacy checks' are disabled on a service/globally or when apikey are extracted in a custom fashion.\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.AuthModule }\n\n## Authentication\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.AuthModule`\n\n### Description\n\nThis plugin applies an authentication module\n\n\n\n### Default configuration\n\n```json\n{\n \"pass_with_apikey\" : false,\n \"auth_module\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.BuildMode }\n\n## Build mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.BuildMode`\n\n### Description\n\nThis plugin displays a build page\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.CanaryMode }\n\n## Canary mode\n\n### Defined on steps\n\n - `PreRoute`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.CanaryMode`\n\n### Description\n\nThis plugin can split a portion of the traffic to canary backends\n\n\n\n### Default configuration\n\n```json\n{\n \"traffic\" : 0.2,\n \"targets\" : [ ],\n \"root\" : \"/\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ContextValidation }\n\n## Context validator\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ContextValidation`\n\n### Description\n\nThis plugin validates the current context using JSONPath validators.\n\nThis plugin let you configure a list of validators that will check if the current call can pass.\nA validator is composed of a [JSONPath](https://goessner.net/articles/JsonPath/) that will tell what to check and a value that is the expected value.\nThe JSONPath will be applied on a document that will look like\n\n```js\n{\n \"snowflake\" : \"1516772930422308903\",\n \"apikey\" : { // current apikey\n \"clientId\" : \"vrmElDerycXrofar\",\n \"clientName\" : \"default-apikey\",\n \"metadata\" : {\n \"foo\" : \"bar\"\n },\n \"tags\" : [ ]\n },\n \"user\" : null, // current user\n \"request\" : {\n \"id\" : 1,\n \"method\" : \"GET\",\n \"headers\" : {\n \"Host\" : \"ctx-validation-next-gen.oto.tools:9999\",\n \"Accept\" : \"*/*\",\n \"User-Agent\" : \"curl/7.64.1\",\n \"Authorization\" : \"Basic dnJtRWxEZXJ5Y1hyb2ZhcjpvdDdOSTkyVGI2Q2J4bWVMYU9UNzJxamdCU2JlRHNLbkxtY1FBcXBjVjZTejh0Z3I1b2RUOHAzYjB5SEVNRzhZ\",\n \"Remote-Address\" : \"127.0.0.1:58929\",\n \"Timeout-Access\" : \"\",\n \"Raw-Request-URI\" : \"/foo\",\n \"Tls-Session-Info\" : \"Session(1650461821330|SSL_NULL_WITH_NULL_NULL)\"\n },\n \"cookies\" : [ ],\n \"tls\" : false,\n \"uri\" : \"/foo\",\n \"path\" : \"/foo\",\n \"version\" : \"HTTP/1.1\",\n \"has_body\" : false,\n \"remote\" : \"127.0.0.1\",\n \"client_cert_chain\" : null\n },\n \"config\" : {\n \"validators\" : [ {\n \"path\" : \"$.apikey.metadata.foo\",\n \"value\" : \"bar\"\n } ]\n },\n \"global_config\" : { ... }, // global config\n \"attrs\" : {\n \"otoroshi.core.SnowFlake\" : \"1516772930422308903\",\n \"otoroshi.core.ElCtx\" : {\n \"requestId\" : \"1516772930422308903\",\n \"requestSnowflake\" : \"1516772930422308903\",\n \"requestTimestamp\" : \"2022-04-20T15:37:01.548+02:00\"\n },\n \"otoroshi.next.core.Report\" : \"otoroshi.next.proxy.NgExecutionReport@277b44e2\",\n \"otoroshi.core.RequestStart\" : 1650461821545,\n \"otoroshi.core.RequestWebsocket\" : false,\n \"otoroshi.core.RequestCounterOut\" : 0,\n \"otoroshi.core.RemainingQuotas\" : {\n \"authorizedCallsPerSec\" : 10000000,\n \"currentCallsPerSec\" : 0,\n \"remainingCallsPerSec\" : 10000000,\n \"authorizedCallsPerDay\" : 10000000,\n \"currentCallsPerDay\" : 2,\n \"remainingCallsPerDay\" : 9999998,\n \"authorizedCallsPerMonth\" : 10000000,\n \"currentCallsPerMonth\" : 269,\n \"remainingCallsPerMonth\" : 9999731\n },\n \"otoroshi.next.core.MatchedRoutes\" : \"MutableList(route_022825450-e97d-42ed-8e22-b23342c1c7c8)\",\n \"otoroshi.core.RequestNumber\" : 1,\n \"otoroshi.next.core.Route\" : { ... }, // current route as json\n \"otoroshi.core.RequestTimestamp\" : \"2022-04-20T15:37:01.548+02:00\",\n \"otoroshi.core.ApiKey\" : { ... }, // current apikey as json\n \"otoroshi.core.User\" : { ... }, // current user as json\n \"otoroshi.core.RequestCounterIn\" : 0\n },\n \"route\" : { ... },\n \"token\" : null // current valid jwt token if one\n}\n```\n\nthe expected value support some syntax tricks like\n\n* `Not(value)` on a string to check if the current value does not equals another value\n* `Regex(regex)` on a string to check if the current value matches the regex\n* `RegexNot(regex)` on a string to check if the current value does not matches the regex\n* `Wildcard(*value*)` on a string to check if the current value matches the value with wildcards\n* `WildcardNot(*value*)` on a string to check if the current value does not matches the value with wildcards\n* `Contains(value)` on a string to check if the current value contains a value\n* `ContainsNot(value)` on a string to check if the current value does not contains a value\n* `Contains(Regex(regex))` on an array to check if one of the item of the array matches the regex\n* `ContainsNot(Regex(regex))` on an array to check if one of the item of the array does not matches the regex\n* `Contains(Wildcard(*value*))` on an array to check if one of the item of the array matches the wildcard value\n* `ContainsNot(Wildcard(*value*))` on an array to check if one of the item of the array does not matches the wildcard value\n* `Contains(value)` on an array to check if the array contains a value\n* `ContainsNot(value)` on an array to check if the array does not contains a value\n\nfor instance to check if the current apikey has a metadata name `foo` with a value containing `bar`, you can write the following validator\n\n```js\n{\n \"path\": \"$.apikey.metadata.foo\",\n \"value\": \"Contains(bar)\"\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"validators\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Cors }\n\n## CORS\n\n### Defined on steps\n\n - `PreRoute`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Cors`\n\n### Description\n\nThis plugin applies CORS rules\n\n\n\n### Default configuration\n\n```json\n{\n \"allow_origin\" : \"*\",\n \"expose_headers\" : [ ],\n \"allow_headers\" : [ ],\n \"allow_methods\" : [ ],\n \"excluded_patterns\" : [ ],\n \"max_age\" : null,\n \"allow_credentials\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.DisableHttp10 }\n\n## Disable HTTP/1.0\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.DisableHttp10`\n\n### Description\n\nThis plugin forbids HTTP/1.0 requests\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.EndlessHttpResponse }\n\n## Endless HTTP responses\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.EndlessHttpResponse`\n\n### Description\n\nThis plugin returns 128 Gb of 0 to the ip addresses is in the list\n\n\n\n### Default configuration\n\n```json\n{\n \"finger\" : false,\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ForceHttpsTraffic }\n\n## Force HTTPS traffic\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ForceHttpsTraffic`\n\n### Description\n\nThis plugin verifies the current request uses HTTPS\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalMaintenanceMode }\n\n## Global Maintenance mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalMaintenanceMode`\n\n### Description\n\nThis plugin displays a maintenance page for every services. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalPerIpAddressThrottling }\n\n## Global per ip address throttling \n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalPerIpAddressThrottling`\n\n### Description\n\nEnforce global per ip address throttling. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GlobalThrottling }\n\n## Global throttling \n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GlobalThrottling`\n\n### Description\n\nEnforce global throttling. Useful when 'legacy checks' are disabled on a service/globally\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.GzipResponseCompressor }\n\n## Gzip compression\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.GzipResponseCompressor`\n\n### Description\n\nThis plugin can compress responses using gzip\n\n\n\n### Default configuration\n\n```json\n{\n \"excluded_patterns\" : [ ],\n \"allowed_list\" : [ \"text/*\", \"application/javascript\", \"application/json\" ],\n \"blocked_list\" : [ ],\n \"buffer_size\" : 8192,\n \"chunked_threshold\" : 102400,\n \"compression_level\" : 5\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.HeadersValidation }\n\n## Headers validation\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.HeadersValidation`\n\n### Description\n\nThis plugin validates the values of incoming request headers\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.IpAddressAllowedList }\n\n## IP allowed list\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.IpAddressAllowedList`\n\n### Description\n\nThis plugin verifies the current request ip address is in the allowed list\n\n\n\n### Default configuration\n\n```json\n{\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.IpAddressBlockList }\n\n## IP block list\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.IpAddressBlockList`\n\n### Description\n\nThis plugin verifies the current request ip address is not in the blocked list\n\n\n\n### Default configuration\n\n```json\n{\n \"addresses\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQ }\n\n## JQ\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQ`\n\n### Description\n\nThis plugin let you transform JSON bodies (in requests and responses) using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"request\" : \".\",\n \"response\" : \"\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQRequest }\n\n## JQ transform request\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQRequest`\n\n### Description\n\nThis plugin let you transform request JSON body using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : \".\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JQResponse }\n\n## JQ transform response\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JQResponse`\n\n### Description\n\nThis plugin let you transform JSON response using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : \".\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JsonToXmlRequest }\n\n## request body json-to-xml\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JsonToXmlRequest`\n\n### Description\n\nThis plugin transform incoming request body from json to xml and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JsonToXmlResponse }\n\n## response body json-to-xml\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JsonToXmlResponse`\n\n### Description\n\nThis plugin transform response body from json to xml and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.JwtVerification }\n\n## Jwt verifiers\n\n### Defined on steps\n\n - `ValidateAccess`\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.JwtVerification`\n\n### Description\n\nThis plugin verifies the current request with one or more jwt verifier\n\n\n\n### Default configuration\n\n```json\n{\n \"verifiers\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MaintenanceMode }\n\n## Maintenance mode\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MaintenanceMode`\n\n### Description\n\nThis plugin displays a maintenance page\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MissingHeadersIn }\n\n## Missing headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MissingHeadersIn`\n\n### Description\n\nThis plugin adds headers (if missing) in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MissingHeadersOut }\n\n## Missing headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MissingHeadersOut`\n\n### Description\n\nThis plugin adds headers (if missing) in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"headers\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.MockResponses }\n\n## Mock Responses\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.MockResponses`\n\n### Description\n\nThis plugin returns mock responses\n\n\n\n### Default configuration\n\n```json\n{\n \"responses\" : [ ],\n \"pass_through\" : true\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OtoroshiChallenge }\n\n## Otoroshi challenge token\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OtoroshiChallenge`\n\n### Description\n\nThis plugin adds a jwt challenge token to the request to a backend and expects a response with a matching token\n\n\n\n### Default configuration\n\n```json\n{\n \"version\" : 2,\n \"ttl\" : 30,\n \"request_header_name\" : null,\n \"response_header_name\" : null,\n \"algo_to_backend\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"algo_from_backend\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n },\n \"state_resp_leeway\" : 10\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OtoroshiInfos }\n\n## Otoroshi info. token\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OtoroshiInfos`\n\n### Description\n\nThis plugin adds a jwt info. token to the request to a backend\n\n\n\n### Default configuration\n\n```json\n{\n \"version\" : \"Latest\",\n \"ttl\" : 30,\n \"header_name\" : null,\n \"algo\" : {\n \"type\" : \"HSAlgoSettings\",\n \"size\" : 512,\n \"secret\" : \"secret\",\n \"base64\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.OverrideHost }\n\n## Override host header\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.OverrideHost`\n\n### Description\n\nThis plugin override the current Host header with the Host of the backend target\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.PublicPrivatePaths }\n\n## Public/Private paths\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.PublicPrivatePaths`\n\n### Description\n\nThis plugin allows or forbid request based on path patterns\n\n\n\n### Default configuration\n\n```json\n{\n \"strict\" : false,\n \"private_patterns\" : [ ],\n \"public_patterns\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.QueryTransformer }\n\n## Query param transformer\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.QueryTransformer`\n\n### Description\n\nThis plugin can modify the query params of the request\n\n\n\n### Default configuration\n\n```json\n{\n \"remove\" : [ ],\n \"rename\" : { },\n \"add\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RBAC }\n\n## RBAC\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RBAC`\n\n### Description\n\nThis plugin check if current user/apikey/jwt token has the right role\n\n\n\n### Default configuration\n\n```json\n{\n \"allow\" : [ ],\n \"deny\" : [ ],\n \"allow_all\" : false,\n \"deny_all\" : false,\n \"jwt_path\" : null,\n \"apikey_path\" : null,\n \"user_path\" : null,\n \"role_prefix\" : null,\n \"roles\" : \"roles\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.ReadOnlyCalls }\n\n## Read only requests\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.ReadOnlyCalls`\n\n### Description\n\nThis plugin verifies the current request only reads data\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Redirection }\n\n## Redirection\n\n### Defined on steps\n\n - `PreRoute`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Redirection`\n\n### Description\n\nThis plugin redirects the current request elsewhere\n\n\n\n### Default configuration\n\n```json\n{\n \"code\" : 303,\n \"to\" : \"https://www.otoroshi.io\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RemoveHeadersIn }\n\n## Remove headers in\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RemoveHeadersIn`\n\n### Description\n\nThis plugin removes headers in the incoming otoroshi request\n\n\n\n### Default configuration\n\n```json\n{\n \"header_names\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RemoveHeadersOut }\n\n## Remove headers out\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RemoveHeadersOut`\n\n### Description\n\nThis plugin removes headers in the otoroshi response\n\n\n\n### Default configuration\n\n```json\n{\n \"header_names\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.Robots }\n\n## Robots\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.Robots`\n\n### Description\n\nThis plugin provides all the necessary tool to handle search engine robots\n\n\n\n### Default configuration\n\n```json\n{\n \"robot_txt_enabled\" : true,\n \"robot_txt_content\" : \"User-agent: *\\nDisallow: /\\n\",\n \"meta_enabled\" : true,\n \"meta_content\" : \"noindex,nofollow,noarchive\",\n \"header_enabled\" : true,\n \"header_content\" : \"noindex, nofollow, noarchive\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.RoutingRestrictions }\n\n## Routing Restrictions\n\n### Defined on steps\n\n - `ValidateAccess`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.RoutingRestrictions`\n\n### Description\n\nThis plugin apply routing restriction `method domain/path` on the current request/route\n\n\n\n### Default configuration\n\n```json\n{\n \"allow_last\" : true,\n \"allowed\" : [ ],\n \"forbidden\" : [ ],\n \"not_found\" : [ ]\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SOAPAction }\n\n## SOAP action\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SOAPAction`\n\n### Description\n\nThis plugin is able to call SOAP actions and expose it as a rest endpoint\n\n\n\n### Default configuration\n\n```json\n{\n \"url\" : null,\n \"envelope\" : \"\",\n \"action\" : null,\n \"preserve_query\" : true,\n \"charset\" : null,\n \"jq_request_filter\" : null,\n \"jq_response_filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SendOtoroshiHeadersBack }\n\n## Send otoroshi headers back\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SendOtoroshiHeadersBack`\n\n### Description\n\nThis plugin adds response header containing useful informations about the current call\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.SnowMonkeyChaos }\n\n## Snow Monkey Chaos\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.SnowMonkeyChaos`\n\n### Description\n\nThis plugin introduce some chaos into you life\n\n\n\n### Default configuration\n\n```json\n{\n \"large_request_fault\" : null,\n \"large_response_fault\" : null,\n \"latency_injection_fault\" : null,\n \"bad_responses_fault\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.StaticResponse }\n\n## Static Response\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.StaticResponse`\n\n### Description\n\nThis plugin returns static responses\n\n\n\n### Default configuration\n\n```json\n{\n \"status\" : 200,\n \"headers\" : { },\n \"body\" : \"\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.TcpTunnel }\n\n## TCP Tunnel\n\n### Defined on steps\n\n - `HandlesTunnel`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.TcpTunnel`\n\n### Description\n\nThis plugin creates TCP tunnels through otoroshi\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.UdpTunnel }\n\n## UDP Tunnel\n\n### Defined on steps\n\n - `HandlesTunnel`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.UdpTunnel`\n\n### Description\n\nThis plugin creates UDP tunnels through otoroshi\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.W3CTracing }\n\n## W3C Trace Context\n\n### Defined on steps\n\n - `TransformRequest`\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.W3CTracing`\n\n### Description\n\nThis plugin propagates W3C Trace Context spans and can export it to Jaeger or Zipkin\n\n\n\n### Default configuration\n\n```json\n{\n \"kind\" : \"noop\",\n \"endpoint\" : \"http://localhost:3333/spans\",\n \"timeout\" : 30000,\n \"baggage\" : { }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XForwardedHeaders }\n\n## X-Forwarded-* headers\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XForwardedHeaders`\n\n### Description\n\nThis plugin adds all the X-Forwarder-* headers to the request for the backend target\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XmlToJsonRequest }\n\n## request body xml-to-json\n\n### Defined on steps\n\n - `TransformRequest`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XmlToJsonRequest`\n\n### Description\n\nThis plugin transform incoming request body from xml to json and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .ng-plugin .plugin-hidden .pl #otoroshi.next.plugins.XmlToJsonResponse }\n\n## response body xml-to-json\n\n### Defined on steps\n\n - `TransformResponse`\n\n### Plugin reference\n\n`cp:otoroshi.next.plugins.XmlToJsonResponse`\n\n### Description\n\nThis plugin transform response body from xml to json and may apply a jq transformation\n\n\n\n### Default configuration\n\n```json\n{\n \"filter\" : null\n}\n```\n\n\n\n\n\n@@@\n\n\n\n\n"},{"name":"engine.md","id":"/next/engine.md","url":"/next/engine.html","title":"New proxy engine","content":"# New proxy engine\n\nStarting from the `1.5.3` release, otoroshi offers a new plugin that implements the next generation of the proxy engine. \nThis engine has been designed based on our 5 years experience building, maintaining and running the previous one. \nIt tries to fix all the drawback we may have encountered during those years and highly improve performances, user experience, reporting and debugging capabilities. \nThe new engine is fully plugin oriented in order to spend CPU cycles only on useful stuff.\nYou can enable this plugin only on some domain names so you can easily A/B test the new engine.\nThe new proxy engine is designed to be more reactive and more efficient generally.\nIt is also designed to be very efficient on path routing where it wasn't the old engines strong suit.\n\n@@@ warning\nThis engine is **experimental** and might not work as expected !\n@@@\n\n## Enabling the new engine\n\nTo enable the new proxy engine on an otoroshi instance, just add the plugin in the `global plugins` section of the danger zone, inject the default configuration, enable it and in `domains` add the values of the desired domains (let say we want to use the new engine on `api.foo.bar`. It is possible to use `*.foo.bar` if that's what you want to do).\n\nThe next time a request hits the `api.foo.bar` domain, the new engine will handle it instead of the previous one.\n\n```json\n{\n \"NextGenProxyEngine\" : {\n \"enabled\" : true,\n \"debug_headers\" : false,\n \"reporting\": true,\n \"domains\" : [ \"api.foo.bar\" ],\n \"deny_domains\" : [ ],\n }\n}\n```\n\nif you need to enable global plugin with the new engine, you can add the following configuration in the `global plugins` configuration object \n\n```javascript\n{\n ...\n \"ng\": {\n \"slots\": [\n {\n \"plugin\": \"cp:otoroshi.next.plugins.W3CTracing\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"baggage\": {\n \"foo\": \"bar\"\n }\n }\n },\n {\n \"plugin\": \"cp:otoroshi.next.plugins.wrappers.RequestSinkWrapper\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"plugin\": \"cp:otoroshi.plugins.apikeys.ClientCredentialService\",\n \"ClientCredentialService\": {\n \"domain\": \"ccs-next-gen.oto.tools\",\n \"expiration\": 3600000,\n \"defaultKeyPair\": \"otoroshi-jwt-signing\",\n \"secure\": false\n }\n }\n }\n ]\n }\n ...\n}\n```\n\n## Entities\n\nThis plugin introduces new entities that will replace (one day maybe) service descriptors:\n\n - `routes`: a unique routing rule based on hostname, path, method and headers that will execute a bunch of plugins\n - `services`: multiple routing rules based on hostname, path, method and headers that will execute the same list of plugins\n - `targets`: how to contact a backend either by using a domain name or an ip address, supports mtls\n - `backends`: a list of targets to contact a backend\n\n## Entities sync\n\nA new behavior introduced for the new proxy engine is the entities sync job. To avoid unecessary operations on the underlying datastore when routing requests, a new job has been setup in otoroshi that synchronize the content of the datastore (at least a part of it) with an in-memory cache. Because of it, the propagation of changes between an admin api call and the actual result on routing can be longer than before. When a node creates, updates, or deletes an entity via the admin api, other nodes need to wait for the next poll to purge the old cached entity and start using the new one. You can change the interval between syncs with the configuration key `otoroshi.next.state-sync-interval` or the env. variable `OTOROSHI_NEXT_STATE_SYNC_INTERVAL`. The default value is `10000` and the unit is `milliseconds`\n\n@@@ warning\nBecause of entities sync, memory consumption of otoroshi will be significantly higher than previous versions. You can use `otoroshi.next.monitor-proxy-state-size=true` config (or `OTOROSHI_NEXT_MONITOR_PROXY_STATE_SIZE` env. variable) to monitor the actual memory size of the entities cache. This will produce the `ng-proxy-state-size-monitoring` metric in standard otoroshi metrics\n@@@\n\n## Automatic conversion\n\nThe new engine uses new entities for its configuration, but in order to facilitate transition between the old world and the new world, all the `service descriptors` of an otoroshi instance are automatically converted live into `routes` periodically. Any `service descriptor` should still work as expected through the new engine while enjoying all the perks.\n\n@@@ warning\nthe experimental nature of the engine can imply unexpected behaviors for converted service descriptors\n@@@\n\n## Routing\n\nthe new proxy engine introduces a new router that has enhanced capabilities and performances. The router can handle thousands of routes declarations without compromising performances.\n\nThe new route allow routes to be matched on a combination of\n\n* hostname\n* path\n* header values\n * where values can be `exact_value`, or `Regex(value_regex)`, or `Wildcard(value_with_*)`\n* query param values\n * where values can be `exact_value`, or `Regex(value_regex)`, or `Wildcard(value_with_*)`\n\npatch matching works \n\n* exactly\n * matches `/api/foo` with `/api/foo` and not with `/api/foo/bar`\n* starting with value (default behavior, like the previous engine)\n * matches `/api/foo` with `/api/foo` but also with `/api/foo/bar`\n\npath matching can also include wildcard paths and even path params\n\n* plain old path: `subdomain.domain.tld/api/users`\n* wildcard path: `subdomain.domain.tld/api/users/*/bills`\n* named path params: `subdomain.domain.tld/api/users/:id/bills`\n* named regex path params: `subdomain.domain.tld/api/users/$id<[0-9]+>/bills`\n\nhostname matching works on \n\n* exact values\n * `subdomain.domain.tld`\n* wildcard values like\n * `*.domain.tld`\n * `subdomain.*.tld`\n\nas path matching can now include named path params, it is possible to perform a ful url rewrite on the target path like \n\n* input: `subdomain.domain.tld/api/users/$id<[0-9]+>/bills`\n* output: `target.domain.tld/apis/v1/basic_users/${req.pathparams.id}/all_bills`\n\n## Plugins\n\nthe new route entity defines a plugin pipline where any plugin can be enabled or not and can be active only on some paths. \nEach plugin slot in the pipeline holds the plugin id and the plugin configuration. \n\nYou can also enable debugging only on a plugin instance instead of the whole route (see [the debugging section](#debugging))\n\n```javascript\n{ \n ...\n \"plugins\" : [ {\n \"enabled\" : true,\n \"debug\" : false,\n \"plugin\" : \"cp:otoroshi.next.plugins.OverrideHost\",\n \"include\" : [ ],\n \"exclude\" : [ ],\n \"config\" : { }\n }, {\n \"enabled\" : true,\n \"debug\" : false,\n \"plugin\" : \"cp:otoroshi.next.plugins.ApikeyCalls\",\n \"include\" : [ ],\n \"exclude\" : [ \"/openapi.json\" ],\n \"config\" : { }\n } ]\n}\n```\n\nyou can find the list of built-in plugins @ref:[here](./built-in-plugins.md)\n\n## Using legacy plugins\n\nif you need to use legacy otoroshi plugins with the new engine, you can use several wrappers in order to do so\n\n* `otoroshi.next.plugins.wrappers.PreRoutingWrapper`\n* `otoroshi.next.plugins.wrappers.AccessValidatorWrapper`\n* `otoroshi.next.plugins.wrappers.RequestSinkWrapper`\n* `otoroshi.next.plugins.wrappers.RequestTransformerWrapper`\n* `otoroshi.next.plugins.wrappers.CompositeWrapper`\n\nto use it, just declare a plugin slot with the right wrapper and in the config, declare the `plugin` you want to use and its configuration like:\n\n```javascript\n{\n \"plugin\": \"cp:otoroshi.next.plugins.wrappers.PreRoutingWrapper\",\n \"enabled\": true,\n \"include\": [],\n \"exclude\": [],\n \"config\": {\n \"plugin\": \"cp:otoroshi.plugins.jwt.JwtUserExtractor\",\n \"JwtUserExtractor\": {\n \"verifier\" : \"$ref\",\n \"strict\" : true,\n \"namePath\" : \"name\",\n \"emailPath\": \"email\",\n \"metaPath\" : null\n }\n }\n}\n```\n\n## Reporting\n\nby default, any request hiting the new engine will generate an execution report with informations about how the request pipeline steps were performed. It is possible to export those reports as `RequestFlowReport` events using classical data exporter. By default, exporting for reports is not enabled, you must enable the `export_reporting` flag on a `route` or `service`.\n\n```javascript\n{\n \"@id\": \"8efac472-07bc-4a80-8d27-4236309d7d01\",\n \"@timestamp\": \"2022-02-15T09:51:25.402+01:00\",\n \"@type\": \"RequestFlowReport\",\n \"@product\": \"otoroshi\",\n \"@serviceId\": \"service_548f13bb-a809-4b1d-9008-fae3b1851092\",\n \"@service\": \"demo-service\",\n \"@env\": \"prod\",\n \"route\": {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\",\n \"name\" : \"hey\",\n \"description\" : \"hey\",\n \"tags\" : [ \"env:prod\" ],\n \"metadata\" : { },\n \"enabled\" : true,\n \"debug_flow\" : true,\n \"export_reporting\" : false,\n \"groups\" : [ \"default\" ],\n \"frontend\" : {\n \"domains\" : [ \"hey-next-gen.oto.tools/\", \"hey.oto.tools/\" ],\n \"strip_path\" : true,\n \"exact\" : false,\n \"headers\" : { },\n \"methods\" : [ ]\n },\n \"backend\" : {\n \"targets\" : [ {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n } ],\n \"target_refs\" : [ ],\n \"root\" : \"/\",\n \"rewrite\" : false,\n \"load_balancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"client\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n }\n },\n \"backend_ref\" : null,\n \"plugins\" : [ ]\n },\n \"report\": {\n \"id\" : \"ab73707b3-946b-4853-92d4-4c38bbaac6d6\",\n \"creation\" : \"2022-02-15T09:51:25.402+01:00\",\n \"termination\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 5,\n \"duration_ns\" : 5905522,\n \"overhead\" : 4,\n \"overhead_ns\" : 4223215,\n \"overhead_in\" : 2,\n \"overhead_in_ns\" : 2687750,\n \"overhead_out\" : 1,\n \"overhead_out_ns\" : 1535465,\n \"state\" : \"Successful\",\n \"steps\" : [ {\n \"task\" : \"start-handling\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085402,\n \"stop_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 177430,\n \"ctx\" : null\n }, {\n \"task\" : \"check-concurrent-requests\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085402,\n \"stop_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 145242,\n \"ctx\" : null\n }, {\n \"task\" : \"find-route\",\n \"start\" : 1644915085402,\n \"start_fmt\" : \"2022-02-15T09:51:25.402+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 497119,\n \"ctx\" : {\n \"found_route\" : {\n \"_loc\" : {\n \"tenant\" : \"default\",\n \"teams\" : [ \"default\" ]\n },\n \"id\" : \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\",\n \"name\" : \"hey\",\n \"description\" : \"hey\",\n \"tags\" : [ \"env:prod\" ],\n \"metadata\" : { },\n \"enabled\" : true,\n \"debug_flow\" : true,\n \"export_reporting\" : false,\n \"groups\" : [ \"default\" ],\n \"frontend\" : {\n \"domains\" : [ \"hey-next-gen.oto.tools/\", \"hey.oto.tools/\" ],\n \"strip_path\" : true,\n \"exact\" : false,\n \"headers\" : { },\n \"methods\" : [ ]\n },\n \"backend\" : {\n \"targets\" : [ {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n } ],\n \"target_refs\" : [ ],\n \"root\" : \"/\",\n \"rewrite\" : false,\n \"load_balancing\" : {\n \"type\" : \"RoundRobin\"\n },\n \"client\" : {\n \"useCircuitBreaker\" : true,\n \"retries\" : 1,\n \"maxErrors\" : 20,\n \"retryInitialDelay\" : 50,\n \"backoffFactor\" : 2,\n \"callTimeout\" : 30000,\n \"callAndStreamTimeout\" : 120000,\n \"connectionTimeout\" : 10000,\n \"idleTimeout\" : 60000,\n \"globalTimeout\" : 30000,\n \"sampleInterval\" : 2000,\n \"proxy\" : { },\n \"customTimeouts\" : [ ],\n \"cacheConnectionSettings\" : {\n \"enabled\" : false,\n \"queueSize\" : 2048\n }\n }\n },\n \"backend_ref\" : null,\n \"plugins\" : [ ]\n },\n \"matched_path\" : \"\",\n \"exact\" : true,\n \"params\" : { },\n \"matched_routes\" : [ \"service_dev_d54f11d0-18e2-4da4-9316-cf47733fd29a\" ]\n }\n }, {\n \"task\" : \"compute-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 105151,\n \"ctx\" : {\n \"disabled_plugins\" : [ ],\n \"filtered_plugins\" : [ ]\n }\n }, {\n \"task\" : \"tenant-check\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 26097,\n \"ctx\" : null\n }, {\n \"task\" : \"check-global-maintenance\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 14132,\n \"ctx\" : null\n }, {\n \"task\" : \"call-before-request-callbacks\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 56671,\n \"ctx\" : null\n }, {\n \"task\" : \"extract-tracking-id\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 5207,\n \"ctx\" : null\n }, {\n \"task\" : \"call-pre-route-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 39786,\n \"ctx\" : null\n }, {\n \"task\" : \"call-access-validator-plugins\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085403,\n \"stop_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 25311,\n \"ctx\" : null\n }, {\n \"task\" : \"enforce-global-limits\",\n \"start\" : 1644915085403,\n \"start_fmt\" : \"2022-02-15T09:51:25.403+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 296617,\n \"ctx\" : {\n \"remaining_quotas\" : {\n \"authorizedCallsPerSec\" : 10000000,\n \"currentCallsPerSec\" : 10000000,\n \"remainingCallsPerSec\" : 10000000,\n \"authorizedCallsPerDay\" : 10000000,\n \"currentCallsPerDay\" : 10000000,\n \"remainingCallsPerDay\" : 10000000,\n \"authorizedCallsPerMonth\" : 10000000,\n \"currentCallsPerMonth\" : 10000000,\n \"remainingCallsPerMonth\" : 10000000\n }\n }\n }, {\n \"task\" : \"choose-backend\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 368899,\n \"ctx\" : {\n \"backend\" : {\n \"id\" : \"127.0.0.1:8081\",\n \"hostname\" : \"127.0.0.1\",\n \"port\" : 8081,\n \"tls\" : false,\n \"weight\" : 1,\n \"protocol\" : \"HTTP/1.1\",\n \"ip_address\" : null,\n \"tls_config\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n }\n }, {\n \"task\" : \"transform-request\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085404,\n \"stop_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 506363,\n \"ctx\" : null\n }, {\n \"task\" : \"call-backend\",\n \"start\" : 1644915085404,\n \"start_fmt\" : \"2022-02-15T09:51:25.404+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 2,\n \"duration_ns\" : 2163470,\n \"ctx\" : null\n }, {\n \"task\" : \"transform-response\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 279887,\n \"ctx\" : null\n }, {\n \"task\" : \"stream-response\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085407,\n \"stop_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 382952,\n \"ctx\" : null\n }, {\n \"task\" : \"trigger-analytics\",\n \"start\" : 1644915085407,\n \"start_fmt\" : \"2022-02-15T09:51:25.407+01:00\",\n \"stop\" : 1644915085408,\n \"stop_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 812036,\n \"ctx\" : null\n }, {\n \"task\" : \"request-success\",\n \"start\" : 1644915085408,\n \"start_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"stop\" : 1644915085408,\n \"stop_fmt\" : \"2022-02-15T09:51:25.408+01:00\",\n \"duration\" : 0,\n \"duration_ns\" : 0,\n \"ctx\" : null\n } ]\n }\n}\n```\n\n## Debugging\n\nwith the new reporting capabilities, the new engine also have debugging capabilities built in. In you enable the `debug_flow` flag on a route (or service), the resulting `RequestFlowReport` will be enriched with contextual informations between each plugins of the route plugin pipeline\n\n@@@ note\nyou can also use the `Try it` feature of the new route designer UI to get debug reports automatically for a specific call\n@@@\n\n## HTTP traffic capture\n\nusing the `capture` flag, a `TrafficCaptureEvent` is generated for each http request/response. This event will contains request and response body. Those events can be exported using @ref:[data exporters](../entities/data-exporters.md) as usual. You can also use the @ref:[GoReplay file exporter](../entities/data-exporters.md#goreplay-file) that is specifically designed to ingest those events and create [GoReplay](https://goreplay.org/) files (`.gor`)\n\n@@@ warning\nthis feature can have actual impact on CPU and RAM consumption\n@@@\n\n```json\n{\n \"@id\": \"d5998b0c4-cb08-43e6-9921-27472c7a56e0\",\n \"@timestamp\": 1651828801115,\n \"@type\": \"TrafficCaptureEvent\",\n \"@product\": \"otoroshi\",\n \"@serviceId\": \"route_2b2670879-131c-423d-b755-470c7b1c74b1\",\n \"@service\": \"test-server\",\n \"@env\": \"prod\",\n \"route\": {\n \"id\": \"route_2b2670879-131c-423d-b755-470c7b1c74b1\",\n \"name\": \"test-server\"\n },\n \"request\": {\n \"id\": \"152250645825034725600000\",\n \"int_id\": 115,\n \"method\": \"POST\",\n \"headers\": {\n \"Host\": \"test-server-next-gen.oto.tools:9999\",\n \"Accept\": \"*/*\",\n \"Cookie\": \"fifoo=fibar\",\n \"User-Agent\": \"curl/7.64.1\",\n \"Content-Type\": \"application/json\",\n \"Content-Length\": \"13\",\n \"Remote-Address\": \"127.0.0.1:57660\",\n \"Timeout-Access\": \"\",\n \"Raw-Request-URI\": \"/\",\n \"Tls-Session-Info\": \"Session(1651828041285|SSL_NULL_WITH_NULL_NULL)\"\n },\n \"cookies\": [\n {\n \"name\": \"fifoo\",\n \"value\": \"fibar\",\n \"path\": \"/\",\n \"domain\": null,\n \"http_only\": true,\n \"max_age\": null,\n \"secure\": false,\n \"same_site\": null\n }\n ],\n \"tls\": false,\n \"uri\": \"/\",\n \"path\": \"/\",\n \"version\": \"HTTP/1.1\",\n \"has_body\": true,\n \"remote\": \"127.0.0.1\",\n \"client_cert_chain\": null,\n \"body\": \"{\\\"foo\\\":\\\"bar\\\"}\"\n },\n \"backend_request\": {\n \"url\": \"http://localhost:3000/\",\n \"method\": \"POST\",\n \"headers\": {\n \"Host\": \"localhost\",\n \"Accept\": \"*/*\",\n \"Cookie\": \"fifoo=fibar\",\n \"User-Agent\": \"curl/7.64.1\",\n \"Content-Type\": \"application/json\",\n \"Content-Length\": \"13\"\n },\n \"version\": \"HTTP/1.1\",\n \"client_cert_chain\": null,\n \"cookies\": [\n {\n \"name\": \"fifoo\",\n \"value\": \"fibar\",\n \"domain\": null,\n \"path\": \"/\",\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": true\n }\n ],\n \"id\": \"152260631569472064900000\",\n \"int_id\": 33,\n \"body\": \"{\\\"foo\\\":\\\"bar\\\"}\"\n },\n \"backend_response\": {\n \"status\": 200,\n \"headers\": {\n \"Date\": \"Fri, 06 May 2022 09:20:01 GMT\",\n \"Connection\": \"keep-alive\",\n \"Set-Cookie\": \"foo=bar\",\n \"Content-Type\": \"application/json\",\n \"Transfer-Encoding\": \"chunked\"\n },\n \"cookies\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\",\n \"domain\": null,\n \"path\": null,\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": false\n }\n ],\n \"id\": \"152260631569472064900000\",\n \"status_txt\": \"OK\",\n \"http_version\": \"HTTP/1.1\",\n \"body\": \"{\\\"headers\\\":{\\\"host\\\":\\\"localhost\\\",\\\"accept\\\":\\\"*/*\\\",\\\"user-agent\\\":\\\"curl/7.64.1\\\",\\\"content-type\\\":\\\"application/json\\\",\\\"cookie\\\":\\\"fifoo=fibar\\\",\\\"content-length\\\":\\\"13\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"/\\\",\\\"body\\\":\\\"{\\\\\\\"foo\\\\\\\":\\\\\\\"bar\\\\\\\"}\\\"}\"\n },\n \"response\": {\n \"id\": \"152250645825034725600000\",\n \"status\": 200,\n \"headers\": {\n \"Date\": \"Fri, 06 May 2022 09:20:01 GMT\",\n \"Connection\": \"keep-alive\",\n \"Set-Cookie\": \"foo=bar\",\n \"Content-Type\": \"application/json\",\n \"Transfer-Encoding\": \"chunked\"\n },\n \"cookies\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\",\n \"domain\": null,\n \"path\": null,\n \"maxAge\": null,\n \"secure\": false,\n \"httpOnly\": false\n }\n ],\n \"status_txt\": \"OK\",\n \"http_version\": \"HTTP/1.1\",\n \"body\": \"{\\\"headers\\\":{\\\"host\\\":\\\"localhost\\\",\\\"accept\\\":\\\"*/*\\\",\\\"user-agent\\\":\\\"curl/7.64.1\\\",\\\"content-type\\\":\\\"application/json\\\",\\\"cookie\\\":\\\"fifoo=fibar\\\",\\\"content-length\\\":\\\"13\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"/\\\",\\\"body\\\":\\\"{\\\\\\\"foo\\\\\\\":\\\\\\\"bar\\\\\\\"}\\\"}\"\n },\n \"user-agent-details\": null,\n \"origin-details\": null,\n \"instance-number\": 0,\n \"instance-name\": \"dev\",\n \"instance-zone\": \"local\",\n \"instance-region\": \"local\",\n \"instance-dc\": \"local\",\n \"instance-provider\": \"local\",\n \"instance-rack\": \"local\",\n \"cluster-mode\": \"Leader\",\n \"cluster-name\": \"otoroshi-leader-9hnv5HUXpbCZD7Ee\"\n}\n```\n\n## openapi import\n\nas the new router offers possibility to match exactly on a single path and a single method, and with the help of the `service` entity, it is now pretty easy to import openapi document as `service` entities. To do that, a new api has been made available to perform the translation. Be aware that this api **DOES NOT** save the entity and just return the result of the translation. \n\n```sh\ncurl -X POST \\\n -H 'Content-Type: application/json' \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n 'http://otoroshi-api.oto.tools:8080/api/experimental/services/_openapi' \\\n -d '{\"domain\":\"oto-api-proxy.oto.tools\",\"openapi\":\"https://raw.githubusercontent.com/MAIF/otoroshi/master/otoroshi/public/openapi.json\"}'\n```\n\n@@@ div { .centered-img }\n\n@@@\n\n"},{"name":"index.md","id":"/next/index.md","url":"/next/index.html","title":"Otoroshi Next","content":"# Otoroshi Next\n\nIn this sections, you will find informations about Otoroshi next \n\n* @ref:[New proxy engine](./engine.md)\n* @ref:[Secrets management](./secrets.md)\n* @ref:[Built in plugins](./built-in-plugins.md)\n\n@@@ index\n\n* [New proxy engine](./engine.md)\n* [Secrets management](./secrets.md)\n* [Built in plugins](./built-in-plugins.md)\n\n@@@\n"},{"name":"secrets.md","id":"/next/secrets.md","url":"/next/secrets.html","title":"Secrets management","content":"# Secrets management\n\n@@@ warning\n\nthis feature is **EXPERIMENTAL** and might not work as expected\n\n@@@\n\nSecrets are generally confidential values that should not appear in plain text in the application. There are several products that help you store, retrieve, and rotate these secrets securely. Otoroshi offers a mechanism to set up references to these secrets in its entities to benefits from the perks of your existing secrets management infrastructure. This feature only work with the @ref:[new proxy engine](./engine.md).\n\nA secret can be anything you want like an apikey secret, a certificate private key or password, a jwt verifier signing key, a password to a proxy, a value for a header, etc.\n\n## Enable secrets management in otoroshi\n\nBy default secrets management is disbaled. You can enable it by setting `otoroshi.vaults.enabled` or `${OTOROSHI_VAULTS_ENABLED}` to `true`.\n\n## Global configuration\n\nSecrets management can be only configured using otoroshi static configuration file (also using jvm args mechanism). \nThe configuration is located at `otoroshi.vaults` where you can find the global configuration of the secrets management system and the configurations for each enabled secrets management backends. Basically it looks like\n\n```conf\nvaults {\n enabled = false\n enabled = ${?OTOROSHI_VAULTS_ENABLED}\n secrets-ttl = 300000 # 5 minutes\n secrets-ttl = ${?OTOROSHI_VAULTS_SECRETS_TTL}\n cached-secrets = 10000\n cached-secrets = ${?OTOROSHI_VAULTS_CACHED_SECRETS}\n read-ttl = 10000 # 10 seconds\n read-ttl = ${?OTOROSHI_VAULTS_READ_TTL}\n # if enabled, only leader nodes fetches the secrets.\n # entities with secret values filled are then sent to workers when they poll the cluster state.\n # only works if `otoroshi.cluster.autoUpdateState=true`\n leader-fetch-only = false\n leader-fetch-only = ${?OTOROSHI_VAULTS_LEADER_FETCH_ONLY}\n env {\n type = \"env\"\n prefix = ${?OTOROSHI_VAULTS_ENV_PREFIX}\n }\n}\n```\n\nyou can see here the global configuration and a default backend configured that can retrieve secrets from environment variables. \n\nThe configuration keys can be used for \n\n- `secrets-ttl`: the amount of milliseconds for a secret to be cached\n- `cached-secrets`: the number of secrets that will be cached on an otoroshi instance\n- `read-ttl`: the timeout (in milliseconds) to read a secret from a backend\n\n## Entities with secrets management\n\nthe entities that support secrets management are the following \n\n- `routes`\n- `services`\n- `service_descriptors`\n- `apikeys`\n- `certificates`\n- `jwt_verifiers`\n- `authentication_modules`\n- `targets`\n- `backends`\n- `tcp_services`\n- `data_exporters`\n\n## Define a reference to a secret\n\nin the previously listed entities, you can define, almost everywhere, references to a secret using the following syntax:\n\n`${vault://name_of_the_vault/secret/of/the/path}`\n\nlet say I define a new apikey with the following value as secret `${vault://my_env/apikey_secret}` with the following secrets management configuration\n\n```conf\nvaults {\n enabled = true\n secrets-ttl = 300000\n cached-secrets = 10000\n read-ttl = 10000\n my_env {\n type = \"env\"\n }\n}\n```\n\nif the machine running otoroshi has an environment variable named `APIKEY_SECRET` with the value `verysecret`, then you will be able to can an api with the defined apikey `client_id` and a `client_secret` value of `verysecret`\n\n```sh\ncurl 'http://my-awesome-api.oto.tools:8080/api/stuff' -u awesome_apikey:verysecret\n```\n\n## Possible backends\n\nOtoroshi comes with the support of several secrets management backends.\n\n### Environment variables\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"env\"\n prefix = \"the_prefix_added_to_the_name_of_the_env_variable\"\n }\n}\n```\n\n### Hashicorp Vault\n\na backend for [Hashicorp Vault](https://www.vaultproject.io/). Right now we only support KV engines.\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"hashicorp-vault\"\n url = \"http://127.0.0.1:8200\"\n mount = \"kv\" # the name of the secret store in vault\n kv = \"v2\" # the version of the kv store (v1 or v2)\n token = \"root\" # the token that can access to your secrets\n }\n}\n```\n\nyou should define your references like `${vault://hashicorp_vault/secret/path/key_name}`.\n\n\n### Azure Key Vault\n\na backend for [Azure Key Vault](https://azure.microsoft.com/en-en/services/key-vault/). Right now we only support secrets and not keys and certificates.\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"azure\"\n url = \"https://keyvaultname.vault.azure.net\"\n api-version = \"7.2\" # the api version of the vault\n tenant = \"xxxx-xxx-xxx\" # your azure tenant id, optional\n client_id = \"xxxxx\" # your azure client_id\n client_secret = \"xxxxx\" # your azure client_secret\n # token = \"xxx\" possible if you have a long lived existing token. will take over tenant / client_id / client_secret\n }\n}\n```\n\nyou should define your references like `${vault://azure_vault/secret_name/secret_version}`. `secret_version` is mandatory\n\n### AWS Secrets Manager\n\na backend for [AWS Secrets Manager](https://aws.amazon.com/en/secrets-manager/)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"aws\"\n access-key = \"key\"\n access-key-secret = \"secret\"\n region = \"eu-west-3\" # the aws region of your secrets management\n }\n}\n```\n\nyou should define your references like `${vault://aws_vault/secret_name/secret_version}`. `secret_version` is optional\n\n### Google Cloud Secrets Manager\n\na backend for [Google Cloud Secrets Manager](https://cloud.google.com/secret-manager)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"gcloud\"\n url = \"https://secretmanager.googleapis.com\"\n apikey = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://gcloud_vault/projects/foo/secrets/bar/versions/the_version}`. `the_version` can be `latest`\n\n### AlibabaCloud Cloud Secrets Manager\n\na backend for [AlibabaCloud Secrets Manager](https://www.alibabacloud.com/help/en/doc-detail/152001.html)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"alibaba-cloud\"\n url = \"https://kms.eu-central-1.aliyuncs.com\"\n access-key-id = \"access-key\"\n access-key-secret = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://alibaba_vault/secret_name}`\n\n\n### Kubernetes Secrets\n\na backend for [Kubernetes secrets](https://kubernetes.io/en/docs/concepts/configuration/secret/)\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"kubernetes\"\n # see the configuration of the kubernetes plugin, \n # by default if the pod if well configured, \n # you don't have to setup anything\n }\n}\n```\n\nyou should define your references like `${vault://k8s_vault/namespace/secret_name/key_name}`. `key_name` is optional. if present, otoroshi will try to lookup `key_name` in the secrets `stringData`, if not defined the secrets `data` will be base64 decoded and used.\n\n\n### Izanami config.\n\na backend for [Izanami config.](https://maif.github.io/izanami/manual/)\n\n\nthe configuration of this backend should be like\n\n```conf\nvaults {\n ...\n name_of_the_vault {\n type = \"izanami\"\n url = \"http://127.0.0.1:8200\"\n client-id = \"client\"\n client-secret = \"secret\"\n }\n}\n```\n\nyou should define your references like `${vault://izanami_vault/the:secret:id/key_name}`. `key_name` is optional if the secret value is not a json object"},{"name":"built-in-plugins.md","id":"/plugins/built-in-plugins.md","url":"/plugins/built-in-plugins.html","title":"Otoroshi built-in plugins","content":"# Otoroshi built-in plugins\n\nOtoroshi provides some plugins out of the box. Here is the available plugins with their documentation and reference configuration\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.AccessLog }\n\n## Access log (CLF)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `AccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged in CLF format.\n\nLog format is the following:\n\n`\"$service\" $clientAddress - \"$userId\" [$timestamp] \"$host $method $path $protocol\" \"$status $statusTxt\" $size $snowflake \"$to\" \"$referer\" \"$userAgent\" $http $duration $errorMsg`\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"AccessLog\": {\n \"enabled\": true,\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"AccessLog\" : {\n \"enabled\" : true,\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.AccessLogJson }\n\n## Access log (JSON)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `AccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged in json format.\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"AccessLog\": {\n \"enabled\": true,\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"AccessLog\" : {\n \"enabled\" : true,\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.accesslog.KafkaAccessLog }\n\n## Kafka access log\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `KafkaAccessLog`\n\n### Description\n\nWith this plugin, any access to a service will be logged as an event in a kafka topic.\n\nThe plugin accepts the following configuration\n\n```json\n{\n \"KafkaAccessLog\": {\n \"enabled\": true,\n \"topic\": \"otoroshi-access-log\",\n \"statuses\": [], // list of status to enable logs, if none, log everything\n \"paths\": [], // list of paths to enable logs, if none, log everything\n \"methods\": [], // list of http methods to enable logs, if none, log everything\n \"identities\": [] // list of identities to enable logs, if none, log everything\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KafkaAccessLog\" : {\n \"enabled\" : true,\n \"topic\" : \"otoroshi-access-log\",\n \"statuses\" : [ ],\n \"paths\" : [ ],\n \"methods\" : [ ],\n \"identities\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.authcallers.BasicAuthCaller }\n\n## Basic Auth. caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `BasicAuthCaller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using basic auth.\n\nThis plugin accepts the following configuration\n\n{\n \"username\" : \"the_username\",\n \"password\" : \"the_password\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Basic %s\"\n}\n\n\n\n### Default configuration\n\n```json\n{\n \"username\" : \"the_username\",\n \"password\" : \"the_password\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Basic %s\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.authcallers.OAuth2Caller }\n\n## OAuth2 caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OAuth2Caller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using OAuth2 client_credential/password flow.\nDo not forget to enable client retry to handle token generation on expire.\n\nThis plugin accepts the following configuration\n\n{\n \"kind\" : \"the oauth2 flow, can be 'client_credentials' or 'password'\",\n \"url\" : \"https://127.0.0.1:8080/oauth/token\",\n \"method\" : \"POST\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Bearer %s\",\n \"jsonPayload\" : false,\n \"clientId\" : \"the client_id\",\n \"clientSecret\" : \"the client_secret\",\n \"scope\" : \"an optional scope\",\n \"audience\" : \"an optional audience\",\n \"user\" : \"an optional username if using password flow\",\n \"password\" : \"an optional password if using password flow\",\n \"cacheTokenSeconds\" : \"the number of second to wait before asking for a new token\",\n \"tlsConfig\" : \"an optional TLS settings object\"\n}\n\n\n\n### Default configuration\n\n```json\n{\n \"kind\" : \"the oauth2 flow, can be 'client_credentials' or 'password'\",\n \"url\" : \"https://127.0.0.1:8080/oauth/token\",\n \"method\" : \"POST\",\n \"headerName\" : \"Authorization\",\n \"headerValueFormat\" : \"Bearer %s\",\n \"jsonPayload\" : false,\n \"clientId\" : \"the client_id\",\n \"clientSecret\" : \"the client_secret\",\n \"scope\" : \"an optional scope\",\n \"audience\" : \"an optional audience\",\n \"user\" : \"an optional username if using password flow\",\n \"password\" : \"an optional password if using password flow\",\n \"cacheTokenSeconds\" : \"the number of second to wait before asking for a new token\",\n \"tlsConfig\" : \"an optional TLS settings object\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.cache.ResponseCache }\n\n## Response Cache\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ResponseCache`\n\n### Description\n\nThis plugin can cache responses from target services in the otoroshi datasstore\nIt also provides a debug UI at `/.well-known/otoroshi/bodylogger`.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ResponseCache\": {\n \"enabled\": true, // enabled cache\n \"ttl\": 300000, // store it for some times (5 minutes by default)\n \"maxSize\": 5242880, // max body size (body will be cut after that)\n \"autoClean\": true, // cleanup older keys when all bigger than maxSize\n \"filter\": { // cache only for some status, method and paths\n \"statuses\": [],\n \"methods\": [],\n \"paths\": [],\n \"not\": {\n \"statuses\": [],\n \"methods\": [],\n \"paths\": []\n }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ResponseCache\" : {\n \"enabled\" : true,\n \"ttl\" : 3600000,\n \"maxSize\" : 52428800,\n \"autoClean\" : true,\n \"filter\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ],\n \"not\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ]\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.clientcert.ClientCertChainHeader }\n\n## Client certificate header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ClientCertChain`\n\n### Description\n\nThis plugin pass client certificate informations to the target in headers.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ClientCertChain\": {\n \"pem\": { // send client cert as PEM format in a header\n \"send\": false,\n \"header\": \"X-Client-Cert-Pem\"\n },\n \"dns\": { // send JSON array of DNs in a header\n \"send\": false,\n \"header\": \"X-Client-Cert-DNs\"\n },\n \"chain\": { // send JSON representation of client cert chain in a header\n \"send\": true,\n \"header\": \"X-Client-Cert-Chain\"\n },\n \"claims\": { // pass JSON representation of client cert chain in the otoroshi JWT token\n \"send\": false,\n \"name\": \"clientCertChain\"\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ClientCertChain\" : {\n \"pem\" : {\n \"send\" : false,\n \"header\" : \"X-Client-Cert-Pem\"\n },\n \"dns\" : {\n \"send\" : false,\n \"header\" : \"X-Client-Cert-DNs\"\n },\n \"chain\" : {\n \"send\" : true,\n \"header\" : \"X-Client-Cert-Chain\"\n },\n \"claims\" : {\n \"send\" : false,\n \"name\" : \"clientCertChain\"\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.defer.DeferPlugin }\n\n## Defer Responses\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `DeferPlugin`\n\n### Description\n\nThis plugin will expect a `X-Defer` header or a `defer` query param and defer the response according to the value in milliseconds.\nThis plugin is some kind of inside joke as one a our customer ask us to make slower apis.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"DeferPlugin\": {\n \"defaultDefer\": 0 // default defer in millis\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"DeferPlugin\" : {\n \"defaultDefer\" : 0\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.discovery.DiscoverySelfRegistrationTransformer }\n\n## Self registration endpoints (service discovery)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin add support for self registration endpoint on a specific service.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.envoy.EnvoyControlPlane }\n\n## Envoy Control Plane (experimental)\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `EnvoyControlPlane`\n\n### Description\n\nThis plugin will expose the otoroshi state to envoy instances using the xDS V3 API`.\n\nRight now, all the features of otoroshi cannot be exposed as is through Envoy.\n\n\n\n### Default configuration\n\n```json\n{\n \"EnvoyControlPlane\" : {\n \"enabled\" : true\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.geoloc.GeolocationInfoEndpoint }\n\n## Geolocation endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: ``none``\n\n### Description\n\nThis plugin will expose current geolocation informations on the following endpoint.\n\n`/.well-known/otoroshi/plugins/geolocation`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.geoloc.GeolocationInfoHeader }\n\n## Geolocation header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `GeolocationInfoHeader`\n\n### Description\n\nThis plugin will send informations extracted by the Geolocation details extractor to the target service in a header.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfoHeader\": {\n \"headerName\": \"X-Geolocation-Info\" // header in which info will be sent\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfoHeader\" : {\n \"headerName\" : \"X-Geolocation-Info\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.hmac.HMACCallerPlugin }\n\n## HMAC caller plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `HMACCallerPlugin`\n\n### Description\n\nThis plugin can be used to call a \"protected\" api by an HMAC signature. It will adds a signature with the secret configured on the plugin.\n The signature string will always the content of the header list listed in the plugin configuration.\n\n\n\n### Default configuration\n\n```json\n{\n \"HMACCallerPlugin\" : {\n \"secret\" : \"my-defaut-secret\",\n \"algo\" : \"HMAC-SHA512\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.izanami.IzanamiCanary }\n\n## Izanami Canary Campaign\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `IzanamiCanary`\n\n### Description\n\nThis plugin allow you to perform canary testing based on an izanami experiment campaign (A/B test).\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"IzanamiCanary\" : {\n \"experimentId\" : \"foo:bar:qix\",\n \"configId\" : \"foo:bar:qix:config\",\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000,\n \"mtls\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"IzanamiCanary\" : {\n \"experimentId\" : \"foo:bar:qix\",\n \"configId\" : \"foo:bar:qix:config\",\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000,\n \"mtls\" : {\n \"certs\" : [ ],\n \"trustedCerts\" : [ ],\n \"mtls\" : false,\n \"loose\" : false,\n \"trustAll\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.izanami.IzanamiProxy }\n\n## Izanami APIs Proxy\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `IzanamiProxy`\n\n### Description\n\nThis plugin exposes routes to proxy Izanami configuration and features tree APIs.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"IzanamiProxy\" : {\n \"path\" : \"/api/izanami\",\n \"featurePattern\" : \"*\",\n \"configPattern\" : \"*\",\n \"autoContext\" : false,\n \"featuresEnabled\" : true,\n \"featuresWithContextEnabled\" : true,\n \"configurationEnabled\" : false,\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"IzanamiProxy\" : {\n \"path\" : \"/api/izanami\",\n \"featurePattern\" : \"*\",\n \"configPattern\" : \"*\",\n \"autoContext\" : false,\n \"featuresEnabled\" : true,\n \"featuresWithContextEnabled\" : true,\n \"configurationEnabled\" : false,\n \"izanamiUrl\" : \"https://izanami.foo.bar\",\n \"izanamiClientId\" : \"client\",\n \"izanamiClientSecret\" : \"secret\",\n \"timeout\" : 5000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.jq.JqBodyTransformer }\n\n## JQ bodies transformer\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `JqBodyTransformer`\n\n### Description\n\nThis plugin let you transform JSON bodies (in requests and responses) using [JQ filters](https://stedolan.github.io/jq/manual/#Basicfilters).\n\nSome JSON variables are accessible by default :\n\n * `$url`: the request url\n * `$path`: the request path\n * `$domain`: the request domain\n * `$method`: the request method\n * `$headers`: the current request headers (with name in lowercase)\n * `$queryParams`: the current request query params\n * `$otoToken`: the otoroshi protocol token (if one)\n * `$inToken`: the first matched JWT token as is (from verifiers, if one)\n * `$token`: the first matched JWT token as is (from verifiers, if one)\n * `$user`: the current user (if one)\n * `$apikey`: the current apikey (if one)\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"JqBodyTransformer\" : {\n \"request\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n },\n \"response\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"JqBodyTransformer\" : {\n \"request\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n },\n \"response\" : {\n \"filter\" : \".\",\n \"included\" : [ ],\n \"excluded\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.jsoup.HtmlPatcher }\n\n## Html Patcher\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `HtmlPatcher`\n\n### Description\n\nThis plugin can inject elements in html pages (in the body or in the head) returned by the service\n\n\n\n### Default configuration\n\n```json\n{\n \"HtmlPatcher\" : {\n \"appendHead\" : [ ],\n \"appendBody\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.log4j.Log4ShellFilter }\n\n## Log4Shell mitigation plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `Log4ShellFilter`\n\n### Description\n\nThis plugin try to detect Log4Shell attacks in request and block them.\n\nThis plugin can accept the following configuration\n\n```javascript\n{\n \"Log4ShellFilter\": {\n \"status\": 200, // the status send back when an attack expression is found\n \"body\": \"\", // the body send back when an attack expression is found\n \"parseBody\": false // enables request body parsing to find attack expression\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"Log4ShellFilter\" : {\n \"status\" : 200,\n \"body\" : \"\",\n \"parseBody\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.loggers.BodyLogger }\n\n## Body logger\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `BodyLogger`\n\n### Description\n\nThis plugin can log body present in request and response. It can just logs it, store in in the redis store with a ttl and send it to analytics.\nIt also provides a debug UI at `/.well-known/otoroshi/bodylogger`.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"BodyLogger\": {\n \"enabled\": true, // enabled logging\n \"log\": true, // just log it\n \"store\": false, // store bodies in datastore\n \"ttl\": 300000, // store it for some times (5 minutes by default)\n \"sendToAnalytics\": false, // send bodies to analytics\n \"maxSize\": 5242880, // max body size (body will be cut after that)\n \"password\": \"password\", // password for the ui, if none, it's public\n \"filter\": { // log only for some status, method and paths\n \"statuses\": [],\n \"methods\": [],\n \"paths\": [],\n \"not\": {\n \"statuses\": [],\n \"methods\": [],\n \"paths\": []\n }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"BodyLogger\" : {\n \"enabled\" : true,\n \"log\" : true,\n \"store\" : false,\n \"ttl\" : 300000,\n \"sendToAnalytics\" : false,\n \"maxSize\" : 5242880,\n \"password\" : \"password\",\n \"filter\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ],\n \"not\" : {\n \"statuses\" : [ ],\n \"methods\" : [ ],\n \"paths\" : [ ]\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.metrics.PrometheusServiceMetrics }\n\n## Prometheus Service Metrics\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `PrometheusServiceMetrics`\n\n### Description\n\nThis plugin collects service metrics and can be used with the `Prometheus Endpoint` (in the Danger Zone) plugin to expose those metrics\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"PrometheusServiceMetrics\": {\n \"includeUri\": false // include http uri in metrics. WARNING this could impliess performance issues, use at your own risks\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"PrometheusServiceMetrics\" : {\n \"includeUri\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.metrics.ServiceMetrics }\n\n## Service Metrics\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `ServiceMetrics`\n\n### Description\n\nThis plugin expose service metrics in Otoroshi global metrics or on a special URL of the service `/.well-known/otoroshi/metrics`.\nMetrics are exposed in json or prometheus format depending on the accept header. You can protect it with an access key defined in the configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ServiceMetrics\": {\n \"accessKeyValue\": \"secret\", // if not defined, public access. Can be ${config.app.health.accessKey}\n \"accessKeyQuery\": \"access_key\"\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ServiceMetrics\" : {\n \"accessKeyValue\" : \"${config.app.health.accessKey}\",\n \"accessKeyQuery\" : \"access_key\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.mirror.MirroringPlugin }\n\n## Mirroring plugin\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `MirroringPlugin`\n\n### Description\n\nThis plugin will mirror every request to other targets\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"MirroringPlugin\": {\n \"enabled\": true, // enabled mirroring\n \"to\": \"https://foo.bar.dev\", // the url of the service to mirror\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"MirroringPlugin\" : {\n \"enabled\" : true,\n \"to\" : \"https://foo.bar.dev\",\n \"captureResponse\" : false,\n \"generateEvents\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.oauth1.OAuth1CallerPlugin }\n\n## OAuth1 caller\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OAuth1Caller`\n\n### Description\n\nThis plugin can be used to call api that are authenticated using OAuth1.\n Consumer key, secret, and OAuth token et OAuth token secret can be pass through the metadata of an api key\n or via the configuration of this plugin.\n\n\n\n### Default configuration\n\n```json\n{\n \"OAuth1Caller\" : {\n \"algo\" : \"HmacSHA512\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.oidc.OIDCHeaders }\n\n## OIDC headers\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `OIDCHeaders`\n\n### Description\n\nThis plugin injects headers containing tokens and profile from current OIDC provider.\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCHeaders\" : {\n \"profile\" : {\n \"send\" : true,\n \"headerName\" : \"X-OIDC-User\"\n },\n \"idtoken\" : {\n \"send\" : false,\n \"name\" : \"id_token\",\n \"headerName\" : \"X-OIDC-Id-Token\",\n \"jwt\" : true\n },\n \"accesstoken\" : {\n \"send\" : false,\n \"name\" : \"access_token\",\n \"headerName\" : \"X-OIDC-Access-Token\",\n \"jwt\" : true\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.security.SecurityTxt }\n\n## Security Txt\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `SecurityTxt`\n\n### Description\n\nThis plugin exposes a special route `/.well-known/security.txt` as proposed at [https://securitytxt.org/](https://securitytxt.org/).\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"SecurityTxt\": {\n \"Contact\": \"contact@foo.bar\", // mandatory, a link or e-mail address for people to contact you about security issues\n \"Encryption\": \"http://url-to-public-key\", // optional, a link to a key which security researchers should use to securely talk to you\n \"Acknowledgments\": \"http://url\", // optional, a link to a web page where you say thank you to security researchers who have helped you\n \"Preferred-Languages\": \"en, fr, es\", // optional\n \"Policy\": \"http://url\", // optional, a link to a policy detailing what security researchers should do when searching for or reporting security issues\n \"Hiring\": \"http://url\", // optional, a link to any security-related job openings in your organisation\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"SecurityTxt\" : {\n \"Contact\" : \"contact@foo.bar\",\n \"Encryption\" : \"https://...\",\n \"Acknowledgments\" : \"https://...\",\n \"Preferred-Languages\" : \"en, fr\",\n \"Policy\" : \"https://...\",\n \"Hiring\" : \"https://...\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.static.StaticResponse }\n\n## Static Response\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `StaticResponse`\n\n### Description\n\nThis plugin returns a static response for any request\n\n\n\n### Default configuration\n\n```json\n{\n \"StaticResponse\" : {\n \"status\" : 200,\n \"headers\" : {\n \"Content-Type\" : \"application/json\"\n },\n \"body\" : \"{\\\"message\\\":\\\"hello world!\\\"}\",\n \"bodyBase64\" : null\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.useragent.UserAgentInfoEndpoint }\n\n## User-Agent endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: ``none``\n\n### Description\n\nThis plugin will expose current user-agent informations on the following endpoint.\n\n`/.well-known/otoroshi/plugins/user-agent`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.useragent.UserAgentInfoHeader }\n\n## User-Agent header\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `UserAgentInfoHeader`\n\n### Description\n\nThis plugin will sent informations extracted by the User-Agent details extractor to the target service in a header.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"UserAgentInfoHeader\": {\n \"headerName\": \"X-User-Agent-Info\" // header in which info will be sent\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"UserAgentInfoHeader\" : {\n \"headerName\" : \"X-User-Agent-Info\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer #otoroshi.plugins.workflow.WorkflowEndpoint }\n\n## Workflow endpoint\n\n\n\n### Infos\n\n* plugin type: `transformer`\n* configuration root: `WorkflowEndpoint`\n\n### Description\n\nThis plugin runs a workflow and return the response\n\n\n\n### Default configuration\n\n```json\n{\n \"WorkflowEndpoint\" : {\n \"workflow\" : { }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.biscuit.BiscuitValidator }\n\n## Biscuit token validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nThis plugin validates a Biscuit token.\n\n\n\n### Default configuration\n\n```json\n{\n \"publicKey\" : \"xxxxxx\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingApikeyValidator }\n\n## Client Certificate + Api Key only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nCheck if a client certificate is present in the request and that the apikey used matches the client certificate.\nYou can set the client cert. DN in an apikey metadata named `allowed-client-cert-dn`\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingHttpValidator }\n\n## Client certificate matching (over http)\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasClientCertMatchingHttpValidator`\n\n### Description\n\nCheck if client certificate matches the following configuration\n\nexpected response from http service is\n\n```json\n{\n \"serialNumbers\": [], // allowed certificated serial numbers\n \"subjectDNs\": [], // allowed certificated DNs\n \"issuerDNs\": [], // allowed certificated issuer DNs\n \"regexSubjectDNs\": [], // allowed certificated DNs matching regex\n \"regexIssuerDNs\": [], // allowed certificated issuer DNs matching regex\n}\n```\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"url\": \"...\", // url for the call\n \"headers\": {}, // http header for the call\n \"ttl\": 600000, // cache ttl,\n \"mtlsConfig\": {\n \"certId\": \"xxxxx\",\n \"mtls\": false,\n \"loose\": false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasClientCertMatchingHttpValidator\" : {\n \"url\" : \"http://foo.bar\",\n \"ttl\" : 600000,\n \"headers\" : { },\n \"mtlsConfig\" : {\n \"certId\" : \"...\",\n \"mtls\" : false,\n \"loose\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertMatchingValidator }\n\n## Client certificate matching\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasClientCertMatchingValidator`\n\n### Description\n\nCheck if client certificate matches the following configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\": {\n \"serialNumbers\": [], // allowed certificated serial numbers\n \"subjectDNs\": [], // allowed certificated DNs\n \"issuerDNs\": [], // allowed certificated issuer DNs\n \"regexSubjectDNs\": [], // allowed certificated DNs matching regex\n \"regexIssuerDNs\": [], // allowed certificated issuer DNs matching regex\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasClientCertMatchingValidator\" : {\n \"serialNumbers\" : [ ],\n \"subjectDNs\" : [ ],\n \"issuerDNs\" : [ ],\n \"regexSubjectDNs\" : [ ],\n \"regexIssuerDNs\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.clientcert.HasClientCertValidator }\n\n## Client Certificate Only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: ``none``\n\n### Description\n\nCheck if a client certificate is present in the request\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.external.ExternalHttpValidator }\n\n## External Http Validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `ExternalHttpValidator`\n\n### Description\n\nCalls an external http service to know if a user has access or not. Uses cache for performances.\n\nThe sent payload is the following:\n\n```json\n{\n \"apikey\": {...},\n \"user\": {...},\n \"service\": : {...},\n \"chain\": \"...\", // PEM cert chain\n \"fingerprints\": [...]\n}\n```\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"ExternalHttpValidator\": {\n \"url\": \"...\", // url for the http call\n \"host\": \"...\", // value of the host header for the call. default is host of the url\n \"goodTtl\": 600000, // ttl in ms for a validated call\n \"badTtl\": 60000, // ttl in ms for a not validated call\n \"method\": \"POST\", // http methode\n \"path\": \"/certificates/_validate\", // http uri path\n \"timeout\": 10000, // http call timeout\n \"noCache\": false, // use cache or not\n \"allowNoClientCert\": false, //\n \"headers\": {}, // headers for the http call if needed\n \"mtlsConfig\": {\n \"certId\": \"xxxxx\",\n \"mtls\": false,\n \"loose\": false\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ExternalHttpValidator\" : {\n \"url\" : \"http://foo.bar\",\n \"host\" : \"api.foo.bar\",\n \"goodTtl\" : 600000,\n \"badTtl\" : 60000,\n \"method\" : \"POST\",\n \"path\" : \"/certificates/_validate\",\n \"timeout\" : 10000,\n \"noCache\" : false,\n \"allowNoClientCert\" : false,\n \"headers\" : { },\n \"mtlsConfig\" : {\n \"certId\" : \"...\",\n \"mtls\" : false,\n \"loose\" : false\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.hmac.HMACValidator }\n\n## HMAC access validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HMACAccessValidator`\n\n### Description\n\nThis plugin can be used to check if a HMAC signature is present and valid in Authorization header.\n\n\n\n### Default configuration\n\n```json\n{\n \"HMACAccessValidator\" : {\n \"secret\" : \"\"\n }\n}\n```\n\n\n\n### Documentation\n\n\n The HMAC signature needs to be set on the `Authorization` or `Proxy-Authorization` header.\n The format of this header should be : `hmac algorithm=\"\", headers=\"
\", signature=\"\"`\n As example, a simple nodeJS call with the expected header\n ```js\n const crypto = require('crypto');\n const fetch = require('node-fetch');\n\n const date = new Date()\n const secret = \"my-secret\" // equal to the api key secret by default\n\n const algo = \"sha512\"\n const signature = crypto.createHmac(algo, secret)\n .update(date.getTime().toString())\n .digest('base64');\n\n fetch('http://myservice.oto.tools:9999/api/test', {\n headers: {\n \"Otoroshi-Client-Id\": \"my-id\",\n \"Otoroshi-Client-Secret\": \"my-secret\",\n \"Date\": date.getTime().toString(),\n \"Authorization\": `hmac algorithm=\"hmac-${algo}\", headers=\"Date\", signature=\"${signature}\"`,\n \"Accept\": \"application/json\"\n }\n })\n .then(r => r.json())\n .then(console.log)\n ```\n In this example, we have an Otoroshi service deployed on http://myservice.oto.tools:9999/api/test, protected by api keys.\n The secret used is the secret of the api key (by default, but you can change it and define a secret on the plugin configuration).\n We send the base64 encoded date of the day, signed by the secret, in the Authorization header. We specify the headers signed and the type of algorithm used.\n You can sign more than one header but you have to list them in the headers fields (each one separate by a space, example : headers=\"Date KeyId\").\n The algorithm used can be HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 or HMAC-SHA512.\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.oidc.OIDCAccessTokenValidator }\n\n## OIDC access_token validator\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `OIDCAccessTokenValidator`\n\n### Description\n\nThis plugin will use the third party apikey configuration and apply it while keeping the apikey mecanism of otoroshi.\nUse it to combine apikey validation and OIDC access_token validation.\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\": {\n \"enabled\": true,\n \"atLeastOne\": false,\n // config is optional and can be either an object config or an array of objects\n \"config\": {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n}\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\" : {\n \"enabled\" : true,\n \"atLeastOne\" : false,\n \"config\" : {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.quotas.InstanceQuotas }\n\n## Instance quotas\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `InstanceQuotas`\n\n### Description\n\nThis plugin will enforce global quotas on the current instance\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"InstanceQuotas\": {\n \"callsPerDay\": -1, // max allowed api calls per day\n \"callsPerMonth\": -1, // max allowed api calls per month\n \"maxDescriptors\": -1, // max allowed service descriptors\n \"maxApiKeys\": -1, // max allowed apikeys\n \"maxGroups\": -1, // max allowed service groups\n \"maxScripts\": -1, // max allowed apikeys\n \"maxCertificates\": -1, // max allowed certificates\n \"maxVerifiers\": -1, // max allowed jwt verifiers\n \"maxAuthModules\": -1, // max allowed auth modules\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"InstanceQuotas\" : {\n \"callsPerDay\" : -1,\n \"callsPerMonth\" : -1,\n \"maxDescriptors\" : -1,\n \"maxApiKeys\" : -1,\n \"maxGroups\" : -1,\n \"maxScripts\" : -1,\n \"maxCertificates\" : -1,\n \"maxVerifiers\" : -1,\n \"maxAuthModules\" : -1\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.quotas.ServiceQuotas }\n\n## Public quotas\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `ServiceQuotas`\n\n### Description\n\nThis plugin will enforce public quotas on the current service\n\n\n\n\n\n\n\n### Default configuration\n\n```json\n{\n \"ServiceQuotas\" : {\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator #otoroshi.plugins.users.HasAllowedUsersValidator }\n\n## Allowed users only\n\n\n\n### Infos\n\n* plugin type: `validator`\n* configuration root: `HasAllowedUsersValidator`\n\n### Description\n\nThis plugin only let allowed users pass\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"HasAllowedUsersValidator\": {\n \"usernames\": [], // allowed usernames\n \"emails\": [], // allowed user email addresses\n \"emailDomains\": [], // allowed user email domains\n \"metadataMatch\": [], // json path expressions to match against user metadata. passes if one match\n \"metadataNotMatch\": [], // json path expressions to match against user metadata. passes if none match\n \"profileMatch\": [], // json path expressions to match against user profile. passes if one match\n \"profileNotMatch\": [], // json path expressions to match against user profile. passes if none match\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"HasAllowedUsersValidator\" : {\n \"usernames\" : [ ],\n \"emails\" : [ ],\n \"emailDomains\" : [ ],\n \"metadataMatch\" : [ ],\n \"metadataNotMatch\" : [ ],\n \"profileMatch\" : [ ],\n \"profileNotMatch\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.ApikeyAuthModule }\n\n## Apikey auth module\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `ApikeyAuthModule`\n\n### Description\n\nThis plugin adds basic auth on service where credentials are valid apikeys on the current service.\n\n\n\n### Default configuration\n\n```json\n{\n \"ApikeyAuthModule\" : {\n \"realm\" : \"apikey-auth-module-realm\",\n \"noneTagIn\" : [ ],\n \"oneTagIn\" : [ ],\n \"allTagsIn\" : [ ],\n \"noneMetaIn\" : [ ],\n \"oneMetaIn\" : [ ],\n \"allMetaIn\" : [ ],\n \"noneMetaKeysIn\" : [ ],\n \"oneMetaKeyIn\" : [ ],\n \"allMetaKeysIn\" : [ ]\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.CertificateAsApikey }\n\n## Client certificate as apikey\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `CertificateAsApikey`\n\n### Description\n\nThis plugin uses client certificate as an apikey. The apikey will be stored for classic apikey usage\n\n\n\n### Default configuration\n\n```json\n{\n \"CertificateAsApikey\" : {\n \"readOnly\" : false,\n \"allowClientIdOnly\" : false,\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"constrainedServicesOnly\" : false,\n \"tags\" : [ ],\n \"metadata\" : { }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.apikeys.ClientCredentialFlowExtractor }\n\n## Client Credential Flow ApiKey extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: ``none``\n\n### Description\n\nThis plugin can extract an apikey from an opaque access_token generate by the `ClientCredentialFlow` plugin\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.biscuit.BiscuitExtractor }\n\n## Apikey from Biscuit token extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: ``none``\n\n### Description\n\nThis plugin extract an from a Biscuit token where the biscuit has an #authority fact 'client_id' containing\napikey client_id and an #authority fact 'client_sign' that is the HMAC256 signature of the apikey client_id with the apikey client_secret\n\n\n\n### Default configuration\n\n```json\n{\n \"publicKey\" : \"xxxxxx\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.discovery.DiscoveryTargetsSelector }\n\n## Service discovery target selector (service discovery)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin select a target in the pool of discovered targets for this service.\nUse in combination with either `DiscoverySelfRegistrationSink` or `DiscoverySelfRegistrationTransformer` to make it work using the `self registration` pattern.\nOr use an implementation of `DiscoveryJob` for the `third party registration pattern`.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.geoloc.IpStackGeolocationInfoExtractor }\n\n## Geolocation details extractor (using IpStack api)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `GeolocationInfo`\n\n### Description\n\nThis plugin extract geolocation informations from ip address using the [IpStack dbs](https://ipstack.com/).\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfo\": {\n \"apikey\": \"xxxxxxx\",\n \"timeout\": 2000, // timeout in ms\n \"log\": false // will log geolocation details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfo\" : {\n \"apikey\" : \"xxxxxxx\",\n \"timeout\" : 2000,\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.geoloc.MaxMindGeolocationInfoExtractor }\n\n## Geolocation details extractor (using Maxmind db)\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `GeolocationInfo`\n\n### Description\n\nThis plugin extract geolocation informations from ip address using the [Maxmind dbs](https://www.maxmind.com/en/geoip2-databases).\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"GeolocationInfo\": {\n \"path\": \"/foo/bar/cities.mmdb\", // file path, can be \"global\"\n \"log\": false // will log geolocation details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"GeolocationInfo\" : {\n \"path\" : \"global\",\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.jwt.JwtUserExtractor }\n\n## Jwt user extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `JwtUserExtractor`\n\n### Description\n\nThis plugin extract a user from a JWT token\n\n\n\n### Default configuration\n\n```json\n{\n \"JwtUserExtractor\" : {\n \"verifier\" : \"\",\n \"strict\" : true,\n \"namePath\" : \"name\",\n \"emailPath\" : \"email\",\n \"metaPath\" : null\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.oidc.OIDCAccessTokenAsApikey }\n\n## OIDC access_token as apikey\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `OIDCAccessTokenAsApikey`\n\n### Description\n\nThis plugin will use the third party apikey configuration to generate an apikey\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"OIDCAccessTokenValidator\": {\n \"enabled\": true,\n \"atLeastOne\": false,\n // config is optional and can be either an object config or an array of objects\n \"config\": {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n}\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"OIDCAccessTokenAsApikey\" : {\n \"enabled\" : true,\n \"atLeastOne\" : false,\n \"config\" : {\n \"enabled\" : true,\n \"quotasEnabled\" : true,\n \"uniqueApiKey\" : false,\n \"type\" : \"OIDC\",\n \"oidcConfigRef\" : \"some-oidc-auth-module-id\",\n \"localVerificationOnly\" : false,\n \"mode\" : \"Tmp\",\n \"ttl\" : 0,\n \"headerName\" : \"Authorization\",\n \"throttlingQuota\" : 100,\n \"dailyQuota\" : 10000000,\n \"monthlyQuota\" : 10000000,\n \"excludedPatterns\" : [ ],\n \"scopes\" : [ ],\n \"rolesPath\" : [ ],\n \"roles\" : [ ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute #otoroshi.plugins.useragent.UserAgentExtractor }\n\n## User-Agent details extractor\n\n\n\n### Infos\n\n* plugin type: `preroute`\n* configuration root: `UserAgentInfo`\n\n### Description\n\nThis plugin extract informations from User-Agent header such as browsser version, OS version, etc.\nThe informations are store in plugins attrs for other plugins to use\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"UserAgentInfo\": {\n \"log\": false // will log user-agent details\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"UserAgentInfo\" : {\n \"log\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.apikeys.ClientCredentialService }\n\n## Client Credential Service\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `ClientCredentialService`\n\n### Description\n\nThis plugin add an an oauth client credentials service (`https://unhandleddomain/.well-known/otoroshi/oauth/token`) to create an access_token given a client id and secret.\n\n```json\n{\n \"ClientCredentialService\" : {\n \"domain\" : \"*\",\n \"expiration\" : 3600000,\n \"defaultKeyPair\" : \"otoroshi-jwt-signing\",\n \"secure\" : true\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"ClientCredentialService\" : {\n \"domain\" : \"*\",\n \"expiration\" : 3600000,\n \"defaultKeyPair\" : \"otoroshi-jwt-signing\",\n \"secure\" : true\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.discovery.DiscoverySelfRegistrationSink }\n\n## Global self registration endpoints (service discovery)\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `DiscoverySelfRegistration`\n\n### Description\n\nThis plugin add support for self registration endpoint on specific hostnames.\n\nThis plugin accepts the following configuration:\n\n\n\n### Default configuration\n\n```json\n{\n \"DiscoverySelfRegistration\" : {\n \"hosts\" : [ ],\n \"targetTemplate\" : { },\n \"registrationTtl\" : 60000\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator }\n\n## Kubernetes admission validator webhook\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: ``none``\n\n### Description\n\nThis plugin exposes a webhook to kubernetes to handle manifests validation\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector }\n\n## Kubernetes sidecar injector webhook\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: ``none``\n\n### Description\n\nThis plugin exposes a webhook to kubernetes to inject otoroshi-sidecar in pods\n\n\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink #otoroshi.plugins.metrics.PrometheusEndpoint }\n\n## Prometheus Endpoint\n\n\n\n### Infos\n\n* plugin type: `sink`\n* configuration root: `PrometheusEndpoint`\n\n### Description\n\nThis plugin exposes metrics collected by `Prometheus Service Metrics` on a `/prometheus` endpoint.\nYou can protect it with an access key defined in the configuration\n\nThis plugin can accept the following configuration\n\n```json\n{\n \"PrometheusEndpoint\": {\n \"accessKeyValue\": \"secret\", // if not defined, public access. Can be ${config.app.health.accessKey}\n \"accessKeyQuery\": \"access_key\",\n \"includeMetrics\": false\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"PrometheusEndpoint\" : {\n \"accessKeyValue\" : \"${config.app.health.accessKey}\",\n \"accessKeyQuery\" : \"access_key\",\n \"includeMetrics\" : false\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesIngressControllerJob }\n\n## Kubernetes Ingress Controller\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin enables Otoroshi as an Ingress Controller\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob }\n\n## Kubernetes Otoroshi CRDs Controller\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin enables Otoroshi CRDs Controller\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.KubernetesToOtoroshiCertSyncJob }\n\n## Kubernetes to Otoroshi certs. synchronizer\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin syncs. TLS secrets from Kubernetes to Otoroshi\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.jobs.kubernetes.OtoroshiToKubernetesCertSyncJob }\n\n## Otoroshi certs. to Kubernetes secrets synchronizer\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `KubernetesConfig`\n\n### Description\n\nThis plugin syncs. Otoroshi certs to Kubernetes TLS secrets\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n### Default configuration\n\n```json\n{\n \"KubernetesConfig\" : {\n \"endpoint\" : \"https://kube.cluster.dev\",\n \"token\" : \"xxx\",\n \"userPassword\" : \"user:password\",\n \"caCert\" : \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n \"trust\" : false,\n \"namespaces\" : [ \"*\" ],\n \"labels\" : { },\n \"namespacesLabels\" : { },\n \"ingressClasses\" : [ \"otoroshi\" ],\n \"defaultGroup\" : \"default\",\n \"ingresses\" : true,\n \"crds\" : true,\n \"coreDnsIntegration\" : false,\n \"coreDnsIntegrationDryRun\" : false,\n \"kubeLeader\" : false,\n \"restartDependantDeployments\" : true,\n \"useProxyState\" : false,\n \"watch\" : true,\n \"syncDaikokuApikeysOnly\" : false,\n \"kubeSystemNamespace\" : \"kube-system\",\n \"coreDnsConfigMapName\" : \"coredns\",\n \"coreDnsDeploymentName\" : \"coredns\",\n \"corednsPort\" : 53,\n \"otoroshiServiceName\" : \"otoroshi-service\",\n \"otoroshiNamespace\" : \"otoroshi\",\n \"clusterDomain\" : \"cluster.local\",\n \"syncIntervalSeconds\" : 60,\n \"coreDnsEnv\" : null,\n \"watchTimeoutSeconds\" : 60,\n \"watchGracePeriodSeconds\" : 5,\n \"mutatingWebhookName\" : \"otoroshi-admission-webhook-injector\",\n \"validatingWebhookName\" : \"otoroshi-admission-webhook-validation\",\n \"meshDomain\" : \"otoroshi.mesh\",\n \"openshiftDnsOperatorIntegration\" : false,\n \"openshiftDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"openshiftDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"openshiftDnsOperatorCoreDnsPort\" : 5353,\n \"kubeDnsOperatorIntegration\" : false,\n \"kubeDnsOperatorCoreDnsNamespace\" : \"otoroshi\",\n \"kubeDnsOperatorCoreDnsName\" : \"otoroshi-dns\",\n \"kubeDnsOperatorCoreDnsPort\" : 5353,\n \"templates\" : {\n \"service-group\" : { },\n \"service-descriptor\" : { },\n \"apikeys\" : { },\n \"global-config\" : { },\n \"jwt-verifier\" : { },\n \"tcp-service\" : { },\n \"certificate\" : { },\n \"auth-module\" : { },\n \"script\" : { },\n \"data-exporters\" : { },\n \"organizations\" : { },\n \"teams\" : { },\n \"admins\" : { },\n \"webhooks\" : { }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-job #otoroshi.plugins.workflow.WorkflowJob }\n\n## Workflow job\n\n\n\n### Infos\n\n* plugin type: `job`\n* configuration root: `WorkflowJob`\n\n### Description\n\nPeriodically run a custom workflow\n\n\n\n### Default configuration\n\n```json\n{\n \"WorkflowJob\" : {\n \"input\" : {\n \"namespace\" : \"otoroshi\",\n \"service\" : \"otoroshi-dns\"\n },\n \"intervalMillis\" : \"60000\",\n \"workflow\" : {\n \"name\" : \"some-workflow\",\n \"description\" : \"a nice workflow\",\n \"tasks\" : [ {\n \"name\" : \"call-dns\",\n \"type\" : \"http\",\n \"request\" : {\n \"method\" : \"PATCH\",\n \"url\" : \"http://${env.KUBERNETES_SERVICE_HOST}:${env.KUBERNETES_SERVICE_PORT}/apis/v1/namespaces/${input.namespace}/services/${input.service}\",\n \"headers\" : {\n \"accept\" : \"application/json\",\n \"content-type\" : \"application/json\",\n \"authorization\" : \"Bearer ${file:///var/run/secrets/kubernetes.io/serviceaccount/token}\"\n },\n \"tls\" : {\n \"mtls\" : true,\n \"trustAll\" : true\n },\n \"body\" : [ {\n \"op\" : \"replace\",\n \"path\" : \"/spec/selector\",\n \"value\" : {\n \"app\" : \"otoroshi\",\n \"component\" : \"dns\"\n }\n } ]\n },\n \"success\" : {\n \"statuses\" : [ 200 ]\n }\n } ]\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-request-handler #otoroshi.next.proxy.ProxyEngine }\n\n## Otoroshi next proxy engine (experimental)\n\n\n\n### Infos\n\n* plugin type: `request-handler`\n* configuration root: `NextGenProxyEngine`\n\n### Description\n\nThis plugin holds the next generation otoroshi proxy engine implementation. This engine is **experimental** and may not work as expected !\n\nYou can active this plugin only on some domain names so you can easily A/B test the new engine.\nThe new proxy engine is designed to be more reactive and more efficient generally.\nIt is also designed to be very efficient on path routing where it wasn't the old engines strong suit.\n\nThe idea is to only rely on plugins to work and avoid losing time with features that are not used in service descriptors.\nAn automated conversion happens for every service descriptor. If the exposed domain is handled by this plugin, it will be served by this plugin.\nThis plugin introduces new entities that will replace (one day maybe) service descriptors:\n\n - `routes`: a unique routing rule based on hostname, path, method and headers that will execute a bunch of plugins\n - `services`: multiple routing rules based on hostname, path, method and headers that will execute the same list of plugins\n - `targets`: how to contact a backend either by using a domain name or an ip address, supports mtls\n - `backends`: a list of targets to contact a backend\n\nas an example, let say you want to use the new engine on your service exposed on `api.foo.bar/api`.\nTo do that, just add the plugin in the `global plugins` section of the danger zone, inject the default configuration,\nenabled it and in `domains` add the value `api.foo.bar` (it is possible to use `*.foo.bar` if that's what you want to do).\nThe next time a request hits the `api.foo.bar` domain, the new engine will handle it instead of the old one.\n\n\n\n### Default configuration\n\n```json\n{\n \"enabled\" : true,\n \"domains\" : [ \"*-next-gen.oto.tools\" ],\n \"deny_domains\" : [ ],\n \"reporting\" : true,\n \"merge_sync_steps\" : true,\n \"export_reporting\" : false,\n \"apply_legacy_checks\" : true,\n \"debug\" : false,\n \"capture\" : false,\n \"captureMaxEntitySize\" : 4194304,\n \"debug_headers\" : false,\n \"routing_strategy\" : \"tree\"\n}\n```\n\n\n\n\n\n@@@\n\n\n@@@ div { .plugin .plugin-hidden .plugin-kind-request-handler #otoroshi.script.ForwardTrafficHandler }\n\n## Forward traffic\n\n\n\n### Infos\n\n* plugin type: `request-handler`\n* configuration root: `ForwardTrafficHandler`\n\n### Description\n\nThis plugin can be use to perform a raw traffic forward to an URL without passing through otoroshi routing\n\n\n\n### Default configuration\n\n```json\n{\n \"ForwardTrafficHandler\" : {\n \"domains\" : {\n \"my.domain.tld\" : {\n \"baseUrl\" : \"https://my.otherdomain.tld\",\n \"secret\" : \"jwt signing secret\",\n \"service\" : {\n \"id\" : \"service id for analytics\",\n \"name\" : \"service name for analytics\"\n }\n }\n }\n }\n}\n```\n\n\n\n\n\n@@@\n\n\n\n\n"},{"name":"create-plugins.md","id":"/plugins/create-plugins.md","url":"/plugins/create-plugins.html","title":"Create plugins","content":"# Create plugins\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated\n@@@\n\nWhen everything has failed and you absolutely need a feature in Otoroshi to make your use case work, there is a solution. Plugins is the feature in Otoroshi that allow you to code how Otoroshi should behave when receiving, validating and routing an http request. With request plugin, you can change request / response headers and request / response body the way you want, provide your own apikey, etc.\n\n## Plugin types\n\nthere are many plugin types explained @ref:[here](./plugins.md) \n\n## Code and signatures\n\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/requestsink.scala#L14-L19\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/routing.scala#L75-L78\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/accessvalidator.scala#L65-L85\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/script.scala#269-L540\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/eventlistener.scala#L27-L48\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/job.scala#L69-L164\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/job.scala#L108-L110\n\n\nfor more information about APIs you can use\n\n* https://www.playframework.com/documentation/2.8.x/api/scala/index.html#package\n* https://www.playframework.com/documentation/2.8.x/api/scala/index.html#play.api.mvc.Results\n* https://github.com/MAIF/otoroshi\n* https://doc.akka.io/docs/akka/2.5/stream/index.html\n* https://doc.akka.io/api/akka/current/akka/stream/index.html\n* https://doc.akka.io/api/akka/current/akka/stream/scaladsl/Source.html\n\n## Plugin examples\n\n@ref:[A lot of plugins](./built-in-plugins.md) comes with otoroshi, you can find them on [github](https://github.com/MAIF/otoroshi/tree/master/otoroshi/app/plugins)\n\n## Writing a plugin from Otoroshi UI\n\nLog into Otoroshi and go to `Settings (cog icon) / Plugins`. Here you can create multiple request transformer scripts and associate it with service descriptor later.\n\n@@@ div { .centered-img }\n\n@@@\n\nwhen you write for instance a transformer in the Otoroshi UI, do the following\n\n```scala\nimport akka.stream.Materializer\nimport env.Env\nimport models.{ApiKey, PrivateAppsUser, ServiceDescriptor}\nimport otoroshi.script._\nimport play.api.Logger\nimport play.api.mvc.{Result, Results}\nimport scala.util._\nimport scala.concurrent.{ExecutionContext, Future}\n\nclass MyTransformer extends RequestTransformer {\n\n val logger = Logger(\"my-transformer\")\n\n // implements the methods you want\n}\n\n// WARN: do not forget this line to provide a working instance of your transformer to Otoroshi\nnew MyTransformer()\n```\n\nYou can use the compile button to check if the script compiles, or code the transformer in your IDE (see next point).\n\nThen go to a service descriptor, scroll to the bottom of the page, and select your transformer in the list\n\n@@@ div { .centered-img }\n\n@@@\n\n## Providing a transformer from Java classpath\n\nYou can write your own transformer using your favorite IDE. Just create an SBT project with the following dependencies. It can be quite handy to manage the source code like any other piece of code, and it avoid the compilation time for the script at Otoroshi startup.\n\n```scala\nlazy val root = (project in file(\".\")).\n settings(\n inThisBuild(List(\n organization := \"com.example\",\n scalaVersion := \"2.12.7\",\n version := \"0.1.0-SNAPSHOT\"\n )),\n name := \"request-transformer-example\",\n libraryDependencies += \"fr.maif\" %% \"otoroshi\" % \"1.x.x\"\n )\n```\n\n@@@ warning\nyou MUST provide plugins that lies in the `otoroshi_plugins` package or in a sub-package of `otoroshi_plugins`. If you do not, your plugin will not be found by otoroshi. for example\n\n```scala\npackage otoroshi_plugins.com.my.company.myplugin\n```\n\nalso you don't have to instanciate your plugin at the end of the file like in the Otoroshi UI\n@@@\n\nWhen your code is ready, create a jar file \n\n```\nsbt package\n```\n\nand add the jar file to the Otoroshi classpath\n\n```sh\njava -cp \"/path/to/transformer.jar:$/path/to/otoroshi.jar\" play.core.server.ProdServerStart\n```\n\nthen, in your service descriptor, you can chose your transformer in the list. If you want to do it from the API, you have to defined the transformerRef using `cp:` prefix like \n\n```json\n{\n \"transformerRef\": \"cp:otoroshi_plugins.my.class.package.MyTransformer\"\n}\n```\n\n## Getting custom configuration from the Otoroshi config. file\n\nLet say you need to provide custom configuration values for a script, then you can customize a configuration file of Otoroshi\n\n```hocon\ninclude \"application.conf\"\n\notoroshi {\n scripts {\n enabled = true\n }\n}\n\nmy-transformer {\n env = \"prod\"\n maxRequestBodySize = 2048\n maxResponseBodySize = 2048\n}\n```\n\nthen start Otoroshi like\n\n```sh\njava -Dconfig.file=/path/to/custom.conf -jar otoroshi.jar\n```\n\nthen, in your transformer, you can write something like \n\n```scala\npackage otoroshi_plugins.com.example.otoroshi\n\nimport akka.stream.Materializer\nimport akka.stream.scaladsl._\nimport akka.util.ByteString\nimport env.Env\nimport models.{ApiKey, PrivateAppsUser, ServiceDescriptor}\nimport otoroshi.script._\nimport play.api.Logger\nimport play.api.mvc.{Result, Results}\nimport scala.util._\nimport scala.concurrent.{ExecutionContext, Future}\n\nclass BodyLengthLimiter extends RequestTransformer {\n\n override def def transformResponseWithCtx(ctx: TransformerResponseContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {\n val max = env.configuration.getOptional[Long](\"my-transformer.maxResponseBodySize\").getOrElse(Long.MaxValue)\n ctx.body.limitWeighted(max)(_.size)\n }\n\n override def transformRequestWithCtx(ctx: TransformerRequestContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {\n val max = env.configuration.getOptional[Long](\"my-transformer.maxRequestBodySize\").getOrElse(Long.MaxValue)\n ctx.body.limitWeighted(max)(_.size)\n }\n}\n```\n\n## Using a library that is not embedded in Otoroshi\n\nJust use the `classpath` option when running Otoroshi\n\n```sh\njava -cp \"/path/to/library.jar:$/path/to/otoroshi.jar\" play.core.server.ProdServerStart\n```\n\nBe carefull as your library can conflict with other libraries used by Otoroshi and affect its stability\n\n## Enabling plugins\n\nplugins can be enabled per service from the service settings page or globally from the danger zone in the plugins section.\n\n## Full example\n\na full external plugin example can be found @link:[here](https://github.com/mathieuancelin/otoroshi-wasmer-plugin)\n"},{"name":"index.md","id":"/plugins/index.md","url":"/plugins/index.html","title":"Otoroshi plugins","content":"# Otoroshi plugins\n\nIn this sections, you will find informations about Otoroshi plugins system\n\n* @ref:[Plugins system](./plugins.md)\n* @ref:[Create plugins](./create-plugins.md)\n* @ref:[Built in plugins](./built-in-plugins.md)\n\n@@@ index\n\n* [Plugins system](./plugins.md)\n* [Create plugins](./create-plugins.md)\n* [Built in plugins](./built-in-plugins.md)\n\n@@@"},{"name":"plugins.md","id":"/plugins/plugins.md","url":"/plugins/plugins.html","title":"Otoroshi plugins system","content":"# Otoroshi plugins system\n\nOtoroshi includes several extension points that allows you to create your own plugins and support stuff not supported by default\n\n## Available plugins\n\n@@@ div { .plugin .script }\n## Request Sink\n### Description\nUsed when no services are matched in Otoroshi. Can reply with any content.\n@@@\n\n@@@ div { .plugin .script }\n## Pre routing\n### Description\nUsed to extract values (like custom apikeys) and provide them to other plugins or Otoroshi engine\n@@@\n\n@@@ div { .plugin .script }\n## Access Validator\n### Description\nUsed to validate if a request can pass or not based on whatever you want\n@@@\n\n@@@ div { .plugin .script }\n## Request Transformer\n### Description\nUsed to transform request, responses and their body. Can be used to return arbitrary content\n@@@\n\n@@@ div { .plugin .script }\n## Event listener\n### Description\nAny plugin type can listen to Otoroshi internal events and react to thems\n@@@\n\n@@@ div { .plugin .script }\n## Job\n### Description\nTasks that can run automatically once, on be scheduled with a cron expression or every defined interval\n@@@\n\n@@@ div { .plugin .script }\n## Exporter\n### Description\nUsed to export events and Otoroshi alerts to an external source\n@@@\n\n@@@ div { .plugin .script }\n## Request handler\n### Description\nUsed to handle traffic without passing through Otoroshi routing and apply own rules\n@@@\n\n@@@ div { .plugin .script }\n## Nano app\n### Description\nUsed to write an api directly in Otoroshi in Scala language\n@@@"},{"name":"chaos-engineering.md","id":"/topics/chaos-engineering.md","url":"/topics/chaos-engineering.html","title":"Chaos engineering with the Snow Monkey","content":"# Chaos engineering with the Snow Monkey\n\nNihonzaru (the Snow Monkey) is the chaos engineering tool provided by Otoroshi. You can access it at `Settings (cog icon) / Snow Monkey`.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Chaos engineering\n\nOtoroshi offers some tools to introduce [chaos engineering](https://principlesofchaos.org/) in your everyday life. With chaos engineering, you will improve the resilience of your architecture by creating faults in production on running systems. With [Nihonzaru (the snow monkey)](https://en.wikipedia.org/wiki/Japanese_macaque) Otoroshi helps you to create faults on http request/response handled by Otoroshi. \n\n@@@ div { .centered-img }\n\n@@@\n\n## Settings\n\n@@@ div { .centered-img }\n\n@@@\n\nThe snow monkey let you define a few settings to work properly :\n\n* **Include user facing apps.**: you want to create fault in production, but maybe you don't want your users to enjoy some nice snow monkey generated error pages. Using this switch let you include of not user facing apps (ui apps). Each service descriptor has a `User facing app switch` that will be used by the snow monkey.\n* **Dry run**: when dry run is enabled, outages will be registered and will generate events and alerts (in the otoroshi eventing system) but requests won't be actualy impacted. It's a good way to prepare applications to the snow monkey habits\n* **Outage strategy**: Either `AllServicesPerGroup` or `OneServicePerGroup`. It means that only one service per group or all services per groups will have `n` outages (see next bullet point) during the snow monkey working period\n* **Outages per day**: during snow monkey working period, each service per group or one service per group will have only `n` outages registered \n* **Working period**: the snow monkey only works during a working period. Here you can defined when it starts and when it stops\n* **Outage duration**: here you can defined the bounds for the random outage duration when an outage is created on a service\n* **Impacted groups**: here you can define a list of service groups impacted by the snow monkey. If none is specified, then all service groups will be impacted\n\n## Faults\n\nWith the snow monkey, you can generate four types of faults\n\n* **Large request fault**: Add trailing bytes at the end of the request body (if one)\n* **Large response fault**: Add trailing bytes at the end of the response body\n* **Latency injection fault**: Add random response latency between two bounds\n* **Bad response injection fault**: Create predefined responses with custom headers, body and status code\n\nEach fault let you define a ratio for impacted requests. If you specify a ratio of `0.2`, then 20% of the requests for the impacte service will be impacted by this fault\n\n@@@ div { .centered-img }\n\n@@@\n\nThen you juste have to start the snow monkey and enjoy the show ;)\n\n@@@ div { .centered-img }\n\n@@@\n\n## Current outages\n\nIn the last section of the snow monkey page, you can see current outages (per service), when they started, their duration, etc ...\n\n@@@ div { .centered-img }\n\n@@@"},{"name":"dev-portal.md","id":"/topics/dev-portal.md","url":"/topics/dev-portal.html","title":"Developer portal with Daikoku","content":"# Developer portal with Daikoku\n\nWhile Otoroshi is the perfect tool to manage your webapps in a technical point of view it lacked of business perspective. This is not the case anymore with Daikoku.\n\nWhile Otoroshi is a standalone, Daikoku is a developer portal which stands in front of Otoroshi and provides some business feature.\n\nWhether you want to use Daikoku for your public APIs, you want to monetize or with your private APIs to provide some documentation, facilitation and self-service feature, it will be the perfect portal for Otoroshi.\n\n@@@div { .plugin .platform }\n## Daikoku\n\nRun your first Daikoku with a simple jar or with one Docker command.\n\n\n
\nTry Daikoku \n
\n@link:[With jar](https://maif.github.io/daikoku/devmanual/getdaikoku/frombinaries.html)\n@link:[With Docker](https://maif.github.io/daikoku/devmanual/getdaikoku/fromdocker.html)\n@@@\n\n@@@div { .plugin .platform }\n## Contribute\n\nDaikoku is opensource, so all contributions are welcome.\n\n\n@link:[Show the repository](https://github.com/MAIF/daikoku)\n@@@\n\n@@@div { .plugin .platform }\n## Documentation\n\nDaikoku and its UI are fully documented.\n\n\n@link:[Read the documentation](https://maif.github.io/daikoku/devmanual/)\n@@@\n\n"},{"name":"events-and-analytics.md","id":"/topics/events-and-analytics.md","url":"/topics/events-and-analytics.html","title":"Events and analytics","content":"# Events and analytics\n\nOtoroshi is a solution fully traced : calls to services, access to UI, creation of resources, etc.\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi\n@@@\n\n## Events\n\n* Analytics event\n* Gateway event\n* TCP event\n* Healthcheck event\n\n## Event log\n\nOtoroshi can read his own exported events from an Elasticsearch instance, set up in the danger zone. Theses events are available from the UI, at the following route: `https://xxxxx/bo/dashboard/events`.\n\nThe `Global events` page display all events of **GatewayEvent** type. This page is a way to quickly read an interval of events and can be used in addition of a Kibana instance.\n\nFor each event, a list of information will be displayed and an additional button `content` to watch the full content of the event, at the JSON format. \n\n## Alerts \n\n* `MaxConcurrentRequestReachedAlert`: happening when the handled requests number are greater than the limit of concurrent requests indicated in the global configuration of Otoroshi\n* `CircuitBreakerOpenedAlert`: happening when the circuit breaker pass from closed to opened\n* `CircuitBreakerClosedAlert`: happening when the circuit breaker pass from opened to closed\n* `SessionDiscardedAlert`: send when an admin discarded an admin sessions\n* `SessionsDiscardedAlert`: send when an admin discarded all admin sessions\n* `PanicModeAlert`: send when panic mode is enabled\n* `OtoroshiExportAlert`: send when otoroshi global configuration is exported\n* `U2FAdminDeletedAlert`: send when an admin has deleted an other admin user\n* `BlackListedBackOfficeUserAlert`: send when a blacklisted user has tried to acccess to the UI\n* `AdminLoggedInAlert`: send when an user admin has logged to the UI\n* `AdminFirstLogin`: send when an user admin has successfully logged to the UI for the first time\n* `AdminLoggedOutAlert`: send when an user admin has logged out from Otoroshi\n* `GlobalConfigModification`: send when an user amdin has changed the global configuration of Otoroshi\n* `RevokedApiKeyUsageAlert`: send when an user admin has revoked an apikey\n* `ServiceGroupCreatedAlert`: send when an user admin has created a service group\n* `ServiceGroupUpdatedAlert`: send when an user admin has updated a service group\n* `ServiceGroupDeletedAlert`: send when an user admin has deleted a service group\n* `ServiceCreatedAlert`: send when an user admin has created a tcp service\n* `ServiceUpdatedAlert`: send when an user admin has updated a tcp service\n* `ServiceDeletedAlert`: send when an user admin has deleted a tcp service\n* `ApiKeyCreatedAlert`: send when an user admin has crated a new apikey\n* `ApiKeyUpdatedAlert`: send when an user admin has updated a new apikey\n* `ApiKeyDeletedAlert`: send when an user admin has deleted a new apikey\n\n## Audit\n\nWith Otoroshi, any admin action and any sucpicious/alert action is recorded. These records are stored in Otoroshi’s datastore (only the last n records, defined by the `otoroshi.events.maxSize` config key). All the records can be send through the analytics mechanism (WebHook, Kafka, Elastic) for external and/or further usage. We recommand sending away those records for security reasons.\n\nOtoroshi keep the following list of information for each executed action:\n\n* `Date`: moment of the action\n* `User`: name of the owner\n* `From`: IP of the concerned user\n* `Action`: action performed by the person. The possible actions are:\n\n * `ACCESS_APIKEY`: User accessed a apikey\n * `ACCESS_ALL_APIKEYS`: User accessed all apikeys\n * `CREATE_APIKEY`: User created a apikey\n * `UPDATE_APIKEY`: User updated a apikey\n * `DELETE_APIKEY`: User deleted a apikey\n * `ACCESS_AUTH_MODULE`: User accessed an Auth. module\n * `ACCESS_ALL_AUTH_MODULES`: User accessed all Auth. modules\n * `CREATE_AUTH_MODULE`: User created an Auth. module\n * `UPDATE_AUTH_MODULE`: User updated an Auth. module\n * `DELETE_AUTH_MODULE`: User deleted an Auth. module\n * `ACCESS_CERTIFICATE`: User accessed a certificate\n * `ACCESS_ALL_CERTIFICATES`: User accessed all certificates\n * `CREATE_CERTIFICATE`: User created a certificate\n * `UPDATE_CERTIFICATE`: User updated a certificate\n * `DELETE_CERTIFICATE`: User deleted a certificate\n * `ACCESS_CLIENT_CERT_VALIDATOR`: User accessed a client cert. validator\n * `ACCESS_ALL_CLIENT_CERT_VALIDATORS`: User accessed all client cert. validators\n * `CREATE_CLIENT_CERT_VALIDATOR`: User created a client cert. validator\n * `UPDATE_CLIENT_CERT_VALIDATOR`: User updated a client cert. validator\n * `DELETE_CLIENT_CERT_VALIDATOR`: User deleted a client cert. validator\n * `ACCESS_DATA_EXPORTER_CONFIG`: User accessed a data exporter config\n * `ACCESS_ALL_DATA_EXPORTER_CONFIG`: User accessed all data exporter config\n * `CREATE_DATA_EXPORTER_CONFIG`: User created a data exporter config\n * `UPDATE_DATA_EXPORTER_CONFIG`: User updated a data exporter config\n * `DELETE_DATA_EXPORTER_CONFIG`: User deleted a data exporter config\n * `ACCESS_GLOBAL_JWT_VERIFIER`: User accessed a global jwt verifier\n * `ACCESS_ALL_GLOBAL_JWT_VERIFIERS`: User accessed all global jwt verifiers\n * `CREATE_GLOBAL_JWT_VERIFIER`: User created a global jwt verifier\n * `UPDATE_GLOBAL_JWT_VERIFIER`: User updated a global jwt verifier\n * `DELETE_GLOBAL_JWT_VERIFIER`: User deleted a global jwt verifier\n * `ACCESS_SCRIPT`: User accessed a script\n * `ACCESS_ALL_SCRIPTS`: User accessed all scripts\n * `CREATE_SCRIPT`: User created a script\n * `UPDATE_SCRIPT`: User updated a script\n * `DELETE_SCRIPT`: User deleted a Script\n * `ACCESS_SERVICES_GROUP`: User accessed a service group\n * `ACCESS_ALL_SERVICES_GROUPS`: User accessed all services groups\n * `CREATE_SERVICE_GROUP`: User created a service group\n * `UPDATE_SERVICE_GROUP`: User updated a service group\n * `DELETE_SERVICE_GROUP`: User deleted a service group\n * `ACCESS_SERVICES_FROM_SERVICES_GROUP`: User accessed all services from a services group\n * `ACCESS_TCP_SERVICE`: User accessed a tcp service\n * `ACCESS_ALL_TCP_SERVICES`: User accessed all tcp services\n * `CREATE_TCP_SERVICE`: User created a tcp service\n * `UPDATE_TCP_SERVICE`: User updated a tcp service\n * `DELETE_TCP_SERVICE`: User deleted a tcp service\n * `ACCESS_TEAM`: User accessed a Team\n * `ACCESS_ALL_TEAMS`: User accessed all teams\n * `CREATE_TEAM`: User created a team\n * `UPDATE_TEAM`: User updated a team\n * `DELETE_TEAM`: User deleted a team\n * `ACCESS_TENANT`: User accessed a Tenant\n * `ACCESS_ALL_TENANTS`: User accessed all tenants\n * `CREATE_TENANT`: User created a tenant\n * `UPDATE_TENANT`: User updated a tenant\n * `DELETE_TENANT`: User deleted a tenant\n * `SERVICESEARCH`: User searched for a service\n * `ACTIVATE_PANIC_MODE`: Admin activated panic mode\n\n\n* `Message`: explicit message about the action (example: the `SERVICESEARCH` action happened when an `user searched for a service`)\n* `Content`: all information at JSON format\n\n## Global metrics\n\nThe global metrics are displayed on the index page of the Otoroshi UI. Otoroshi provides information about :\n\n* the number of requests served\n* the amount of data received and sended\n* the number of concurrent requests\n* the number of requests per second\n* the current overhead\n\nMore metrics can be found on the **Global analytics** page (available at https://xxxxxx/bo/dashboard/stats).\n\n## Monitoring services\n\nOnce you have declared services, you can monitor them with Otoroshi. \n\nLet's starting by setup Otoroshi to push events to an elastic cluster via a data exporter. Then you will can setup Otoroshi events read from an elastic cluster. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (read)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service healthcheck\n\nIf you have defined an health check URL in the service descriptor, you can access the health check page from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service live stats\n\nYou can also monitor live stats like total of served request, average response time, average overhead, etc. The live stats page can be accessed from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service analytics\n\nYou can also get some aggregated metrics. The analytics page can be accessed from the sidebar of the service page.\n\n@@@ div { .centered-img }\n\n@@@\n\n## New proxy engine\n\n### Debug reporting\n\nwhen using the @ref:[new proxy engine](../next/engine.md), when a route or the global config. enables traffic capture using the `debug_flow` flag, events of type `RequestFlowReport` are generated\n\n### Traffic capture\n\nwhen using the @ref:[new proxy engine](../next/engine.md), when a route or the global config. enables traffic capture using the `capture` flag, events of type `TrafficCaptureEvent` are generated. It contains everything that compose otoroshi input http request and output http responses\n"},{"name":"expression-language.md","id":"/topics/expression-language.md","url":"/topics/expression-language.html","title":"Expression language","content":"# Expression language\n\n- [Documentation and examples](#documentation-and-examples)\n- [Test the expression language](#test-the-expression-language)\n\nThe expression language provides an important mechanism for accessing and manipulating Otoroshi data on different inputs. For example, with this mechanism, you can mapping a claim of an inconming token directly in a claim of a generated token (using @ref:[JWT verifiers](../entities/jwt-verifiers.md)). You can add information of the service descriptor traversed such as the domain of the service or the name of the service. This information can be useful on the backend service.\n\n## Documentation and examples\n\n@@@div { #expressions }\n \n@@@\n\nIf an input contains a string starting by `${`, Otoroshi will try to evaluate the content. If the content doesn't match a known expression,\nthe 'bad-expr' value will be set.\n\n## Test the expression language\n\nYou can test to get the same values than the right part by creating these following services. \n\n```sh\n# Let's start by downloading the latest Otoroshi.\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'\n\n# Once downloading, run Otoroshi.\njava -Dotoroshi.adminPassword=password -jar otoroshi.jar \n\n# Create a proxy of the mirror.otoroshi.io on http://myservice.oto.tools:8080\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/services \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"enforceSecureCommunication\":false,\"forceHttps\":false,\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"id\":\"expression-language-api-service\",\"name\":\"expression-language\",\"description\":\"expression-language\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"api\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[],\"privatePatterns\":[\"/.*\"],\"kind\":\"ServiceDescriptor\",\"additionalHeaders\":{\"my-expr-header.date\":\"${date}\",\"my-expr-header.date-with-format\":\"${date.format('yyy-MM-dd')}\",\"my-expr-header.request.full-url\":\"${req.fullUrl}\",\"my-expr-header.request.path\":\"${req.path}\",\"my-expr-header.request.uri\":\"${req.uri}\",\"my-expr-header.request.host\":\"${req.host}\",\"my-expr-header.request.domain\":\"${req.domain}\",\"my-expr-header.request.method\":\"${req.method}\",\"my-expr-header.request.protocol\":\"${req.protocol}\",\"my-expr-header.request.unknown-header\":\"${req.headers.foob:default value}\",\"my-expr-header.request.header\":\"${req.headers.foo}\",\"my-expr-header.request.unknown-query\":\"${req.query.foob:default value}\",\"my-expr-header.request.query\":\"${req.query.foo}\",\"my-expr-header.service-domain\":\"${service.domain}\",\"my-expr-header.service-subdomain\":\"${service.subdomain}\",\"my-expr-header.service-tld\":\"${service.tld}\",\"my-expr-header.service-env\":\"${service.env}\",\"my-expr-header.service-id\":\"${service.id}\",\"my-expr-header.service-name\":\"${service.name}\",\"my-expr-header.service-unknown-group\":\"${service.groups['0':'unkown group']}\",\"my-expr-header.service-group\":\"${service.groups['0']}\",\"my-expr-header.service-unknown-metadata\":\"${service.metadata.test:default-value}\",\"my-expr-header.service-metadata\":\"${service.metadata.foo}\",\"my-expr-header.apikey.name\":\"${apikey.name}\",\"my-expr-header.apikey.id\":\"${apikey.id}\",\"my-expr-header.apikey.unknown-metadata\":\"${apikey.metadata.myfield:default value}\",\"my-expr-header.apikey.metadata\":\"${apikey.metadata.foo}\",\"my-expr-header.apikey.unknown-tag\":\"${apikey.tags['0':'no-found-tag']}\",\"my-expr-header.apikey.tag\":\"${apikey.tags['0']}\",\"my-expr-header.token.replace-header-value\":\"${token.foo.replace('o','a')}\",\"my-expr-header.token.replace-header-all-value\":\"${token.foo.replaceAll('o','a')}\",\"my-expr-header.token.unknown-fields\":\"${token.foob|token.foob2:not-found}\",\"my-expr-header.token.foo-field\":\"${token.foob|token.foo}\",\"my-expr-header.token.unknown-foo-field\":\"${token.foob:not-found-foob}\",\"my-expr-header.token.unknown-foo\":\"${token.foo}\",\"my-expr-header.env.unknown-field\":\"${env.java_h:not-found-java_h}\",\"my-expr-header.env.path\":\"${env.PATH}\",\"my-expr-header.config.unknown-port-field\":\"${config.http.ports:not-found}\",\"my-expr-header.config.port\":\"${config.http.port}\",\"my-expr-header.ctx.replace-field-value\":\"${ctx.foo.replace('o','a')}\",\"my-expr-header.ctx.replace-field-all-value\":\"${ctx.foo.replaceAll('o','a')}\",\"my-expr-header.ctx.unknown-fields\":\"${ctx.foob|ctx.foot:not-found}\",\"my-expr-header.ctx.foo-field\":\"${ctx.foob|ctx.foo}\",\"my-expr-header.ctx.default-value\":\"${ctx.foob:other}\",\"my-expr-header.ctx.foo\":\"${ctx.foo}\",\"my-expr-header.ctx.useragent\":\"${ctx.useragent.foo}\",\"my-expr-header.ctx.geolocation\":\"${ctx.geolocation.foo}\"}}\nEOF\n\n# Create an authentication module to protect the next service.\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/auths \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"type\":\"basic\",\"id\":\"auth_mod_in_memory_auth\",\"name\":\"in-memory-auth\",\"desc\":\"in-memory-auth\",\"users\":[{\"name\":\"User Otoroshi\",\"password\":\"$2a$10$oIf4JkaOsfiypk5ZK8DKOumiNbb2xHMZUkYkuJyuIqMDYnR/zXj9i\",\"email\":\"user@foo.bar\",\"metadata\":{\"username\":\"roger\"},\"tags\":[\"foo\"],\"webauthn\":null,\"rights\":[{\"tenant\":\"*:r\",\"teams\":[\"*:r\"]}]}],\"sessionCookieValues\":{\"httpOnly\":true,\"secure\":false}}\nEOF\n\n# Create the same proxy but protected by an authentication memory module (in order to retrieve the user's information after they have successfully logged in)\ncurl -X POST http://otoroshi-api.oto.tools:8080/api/services \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n-d @- <<'EOF'\n{\"enforceSecureCommunication\":false,\"forceHttps\":false,\"_loc\":{\"tenant\":\"default\",\"teams\":[\"default\"]},\"groupId\":\"default\",\"groups\":[\"default\"],\"id\":\"expression-language-webapp\",\"name\":\"webapp\",\"description\":\"webapp\",\"env\":\"prod\",\"domain\":\"oto.tools\",\"subdomain\":\"webapp\",\"targetsLoadBalancing\":{\"type\":\"RoundRobin\"},\"targets\":[{\"host\":\"mirror.otoroshi.io\",\"scheme\":\"https\",\"weight\":1,\"mtlsConfig\":{\"certs\":[],\"trustedCerts\":[],\"mtls\":false,\"loose\":false,\"trustAll\":false},\"tags\":[],\"metadata\":{},\"protocol\":\"HTTP\\/1.1\",\"predicate\":{\"type\":\"AlwaysMatch\"},\"ipAddress\":null}],\"root\":\"\\/\",\"authConfigRef\":\"auth_mod_in_memory_auth\",\"matchingRoot\":null,\"stripPath\":true,\"enabled\":true,\"secComHeaders\":{\"claimRequestName\":null,\"stateRequestName\":null,\"stateResponseName\":null},\"publicPatterns\":[\"/.*\"],\"privateApp\":true,\"privatePatterns\":[],\"kind\":\"ServiceDescriptor\",\"additionalHeaders\":{\"my-expr-header.user\":\"${user.name}\",\"my-expr-header.user.email\":\"${user.email}\",\"my-expr-header.user.unknown-metadata\":\"${user.metadata.foo:'not-found'}\",\"my-expr-header.user.metadata\":\"${user.metadata.username}\",\"my-expr-header.user.unknown-profile-field\":\"${user.profile.username:'not-found'}\",\"my-expr-header.user.profile-field\":\"${user.profile.name}\"}}\nEOF\n```\n\nThen try to call the first service.\n\n```sh\ncurl http://api.oto.tools:8080/api/\\?foo\\=bar \\\n-H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJmb28iOiJiYXIifQ.lV130dFXR3bNtWBkwwf9dLmfsRVmnZhfYF9gvAaRzF8\" \\\n-H \"Otoroshi-Client-Id: admin-api-apikey-id\" \\\n-H \"Otoroshi-Client-Secret: admin-api-apikey-secret\" \\\n-H \"foo: bar\" | jq\n```\n\nThis will returns the list of the received headers by the mirror.\n\n```json\n{\n ...\n \"headers\": {\n ...\n \"my-expr-header.date\": \"2021-11-26T10:54:51.112+01:00\",\n \"my-expr-header.ctx.foo\": \"no-ctx-foo\",\n \"my-expr-header.env.path\": \"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\",\n \"my-expr-header.apikey.id\": \"admin-api-apikey-id\",\n \"my-expr-header.apikey.tag\": \"one-tag\",\n \"my-expr-header.service-id\": \"expression-language-api-service\",\n \"my-expr-header.apikey.name\": \"Otoroshi Backoffice ApiKey\",\n \"my-expr-header.config.port\": \"8080\",\n \"my-expr-header.request.uri\": \"/api/?foo=bar\",\n \"my-expr-header.service-env\": \"prod\",\n \"my-expr-header.service-tld\": \"oto.tools\",\n \"my-expr-header.request.host\": \"api.oto.tools:8080\",\n \"my-expr-header.request.path\": \"/api/\",\n \"my-expr-header.service-name\": \"expression-language\",\n \"my-expr-header.ctx.foo-field\": \"no-ctx-foob-foo\",\n \"my-expr-header.ctx.useragent\": \"no-ctx-useragent.foo\",\n \"my-expr-header.request.query\": \"bar\",\n \"my-expr-header.service-group\": \"default\",\n \"my-expr-header.request.domain\": \"api.oto.tools\",\n \"my-expr-header.request.header\": \"bar\",\n \"my-expr-header.request.method\": \"GET\",\n \"my-expr-header.service-domain\": \"api.oto.tools\",\n \"my-expr-header.apikey.metadata\": \"bar\",\n \"my-expr-header.ctx.geolocation\": \"no-ctx-geolocation.foo\",\n \"my-expr-header.token.foo-field\": \"no-token-foob-foo\",\n \"my-expr-header.date-with-format\": \"2021-11-26\",\n \"my-expr-header.request.full-url\": \"http://api.oto.tools:8080/api/?foo=bar\",\n \"my-expr-header.request.protocol\": \"http\",\n \"my-expr-header.service-metadata\": \"no-meta-foo\",\n \"my-expr-header.ctx.default-value\": \"other\",\n \"my-expr-header.env.unknown-field\": \"not-found-java_h\",\n \"my-expr-header.service-subdomain\": \"api\",\n \"my-expr-header.token.unknown-foo\": \"no-token-foo\",\n \"my-expr-header.apikey.unknown-tag\": \"one-tag\",\n \"my-expr-header.ctx.unknown-fields\": \"not-found\",\n \"my-expr-header.token.unknown-fields\": \"not-found\",\n \"my-expr-header.request.unknown-query\": \"default value\",\n \"my-expr-header.service-unknown-group\": \"default\",\n \"my-expr-header.request.unknown-header\": \"default value\",\n \"my-expr-header.apikey.unknown-metadata\": \"default value\",\n \"my-expr-header.ctx.replace-field-value\": \"no-ctx-foo\",\n \"my-expr-header.token.unknown-foo-field\": \"not-found-foob\",\n \"my-expr-header.service-unknown-metadata\": \"default-value\",\n \"my-expr-header.config.unknown-port-field\": \"not-found\",\n \"my-expr-header.token.replace-header-value\": \"no-token-foo\",\n \"my-expr-header.ctx.replace-field-all-value\": \"no-ctx-foo\",\n \"my-expr-header.token.replace-header-all-value\": \"no-token-foo\",\n }\n}\n```\n\nThen try the second call to the webapp. Navigate on your browser to `http://webapp.oto.tools:8080`. Continue with `user@foo.bar` as user and `password` as credential.\n\nThis should output:\n\n```json\n{\n ...\n \"headers\": {\n ...\n \"my-expr-header.user\": \"User Otoroshi\",\n \"my-expr-header.user.email\": \"user@foo.bar\",\n \"my-expr-header.user.metadata\": \"roger\",\n \"my-expr-header.user.profile-field\": \"User Otoroshi\",\n \"my-expr-header.user.unknown-metadata\": \"not-found\",\n \"my-expr-header.user.unknown-profile-field\": \"not-found\",\n }\n}\n```"},{"name":"index.md","id":"/topics/index.md","url":"/topics/index.html","title":"Detailed topics","content":"# Detailed topics\n\nIn this sections, you will find informations about various Otoroshi topics \n\n* @ref:[Chaos engineering](./chaos-engineering.md)\n* @ref:[TLS](./tls.md)\n* @ref:[Otoroshi's PKI](./pki.md)\n* @ref:[Monitoring](./monitoring.md)\n* @ref:[Events and analytics](./events-and-analytics.md)\n* @ref:[Developer portal with Daikoku](./dev-portal.md)\n* @ref:[Sessions management](./sessions-mgmt.md)\n* @ref:[The Otoroshi communication protocol](./otoroshi-protocol.md)\n* @ref:[Expression language](./expression-language.md)\n* @ref:[Otoroshi user rights](./user-rights.md)\n\n@@@ index\n\n* [Chaos engineering](./chaos-engineering.md)\n* [TLS](./tls.md)\n* [Otoroshi's PKI](./pki.md)\n* [Monitoring](./monitoring.md)\n* [Events and analytics](./events-and-analytics.md)\n* [Developer portal with Daikoku](./dev-portal.md)\n* [Sessions management](./sessions-mgmt.md)\n* [The Otoroshi communication protocol](./otoroshi-protocol.md)\n* [Expression language](./expression-language.md)\n* [Otoroshi user rights](./user-rights.md)\n \n@@@\n"},{"name":"monitoring.md","id":"/topics/monitoring.md","url":"/topics/monitoring.html","title":"Monitoring","content":"# Monitoring\n\nThe Otoroshi API exposes two endpoints to know more about instance health. All the following endpoint are exposed on the instance host through it's ip address. It is also exposed on the otoroshi api hostname and the otoroshi backoffice hostname\n\n* `/health`: the health of the Otoroshi instance\n* `/metrics`: the metrics of the Otoroshi instance, either in JSON or Prometheus format using the `Accept` header (with `application/json` / `application/prometheus` values) or the `format` query param (with `json` or `prometheus` values)\n* `/live`: returns an http 200 response `{\"live\": true}` when the service is alive\n* `/ready`: return an http 200 response `{\"ready\": true}` when the instance is ready to accept traffic (certs synced, plugins compiled, etc). if not, returns http 503 `{\"ready\": false}`\n* `/startup`: return an http 200 response `{\"started\": true}` when the instance is ready to accept traffic (certs synced, plugins compiled, etc). if not, returns http 503 `{\"started\": false}`\n\nthose routes are also available on any hostname leading to otoroshi with a twist in the URL\n\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/health\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/metrics\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/live\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/ready\n* http://xxxxxxxx.xxxxx.xx/.well-known/otoroshi/monitoring/startup\n\n## Endpoints security\n\nThe two endpoints are exposed publicly on the Otoroshi admin api. But you can remove the corresponding public pattern and query the endpoints using standard apikeys. If you don't want to use apikeys but don't want to expose the endpoints publicly, you can defined two config. variables (`otoroshi.health.accessKey` or `HEALTH_ACCESS_KEY` and `otoroshi.metrics.accessKey` or `OTOROSHI_METRICS_ACCESS_KEY`) that will hold an access key for the endpoints. Then you can call the endpoints with an `access_key` query param with the value defined in the config. If you don't defined `otoroshi.metrics.accessKey` but define `otoroshi.health.accessKey`, `otoroshi.metrics.accessKey` will have the value of `otoroshi.health.accessKey`.\n \n## Examples\n\nlet say `otoroshi.health.accessKey` has value `MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY`\n\n```sh\n$ curl http://otoroshi-api.oto.tools:8080/health\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n{\"otoroshi\":\"healthy\",\"datastore\":\"healthy\"}\n\n$ curl -H 'Accept: application/json' http://otoroshi-api.oto.tools:8080/metrics\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n{\"version\":\"4.0.0\",\"gauges\":{\"attr.app.commit\":{\"value\":\"xxxx\"},\"attr.app.id\":{\"value\":\"xxxx\"},\"attr.cluster.mode\":{\"value\":\"Leader\"},\"attr.cluster.name\":{\"value\":\"otoroshi-leader-0\"},\"attr.instance.env\":{\"value\":\"prod\"},\"attr.instance.id\":{\"value\":\"xxxx\"},\"attr.instance.number\":{\"value\":\"0\"},\"attr.jvm.cpu.usage\":{\"value\":136},\"attr.jvm.heap.size\":{\"value\":1409},\"attr.jvm.heap.used\":{\"value\":112},\"internals.0.concurrent-requests\":{\"value\":1},\"internals.global.throttling-quotas\":{\"value\":2},\"jvm.attr.name\":{\"value\":\"2085@xxxx\"},\"jvm.attr.uptime\":{\"value\":2296900},\"jvm.attr.vendor\":{\"value\":\"JDK11\"},\"jvm.gc.PS-MarkSweep.count\":{\"value\":3},\"jvm.gc.PS-MarkSweep.time\":{\"value\":261},\"jvm.gc.PS-Scavenge.count\":{\"value\":12},\"jvm.gc.PS-Scavenge.time\":{\"value\":161},\"jvm.memory.heap.committed\":{\"value\":1477967872},\"jvm.memory.heap.init\":{\"value\":1690304512},\"jvm.memory.heap.max\":{\"value\":3005218816},\"jvm.memory.heap.usage\":{\"value\":0.03916456777568639},\"jvm.memory.heap.used\":{\"value\":117698096},\"jvm.memory.non-heap.committed\":{\"value\":166445056},\"jvm.memory.non-heap.init\":{\"value\":7667712},\"jvm.memory.non-heap.max\":{\"value\":994050048},\"jvm.memory.non-heap.usage\":{\"value\":0.1523920694986979},\"jvm.memory.non-heap.used\":{\"value\":151485344},\"jvm.memory.pools.CodeHeap-'non-nmethods'.committed\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-nmethods'.max\":{\"value\":5832704},\"jvm.memory.pools.CodeHeap-'non-nmethods'.usage\":{\"value\":0.28408093398876405},\"jvm.memory.pools.CodeHeap-'non-nmethods'.used\":{\"value\":1656960},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.committed\":{\"value\":11796480},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.max\":{\"value\":122912768},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.usage\":{\"value\":0.09536102872567315},\"jvm.memory.pools.CodeHeap-'non-profiled-nmethods'.used\":{\"value\":11721088},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.committed\":{\"value\":37355520},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.init\":{\"value\":2555904},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.max\":{\"value\":122912768},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.usage\":{\"value\":0.2538573047187417},\"jvm.memory.pools.CodeHeap-'profiled-nmethods'.used\":{\"value\":31202304},\"jvm.memory.pools.Compressed-Class-Space.committed\":{\"value\":14942208},\"jvm.memory.pools.Compressed-Class-Space.init\":{\"value\":0},\"jvm.memory.pools.Compressed-Class-Space.max\":{\"value\":367001600},\"jvm.memory.pools.Compressed-Class-Space.usage\":{\"value\":0.033858838762555805},\"jvm.memory.pools.Compressed-Class-Space.used\":{\"value\":12426248},\"jvm.memory.pools.Metaspace.committed\":{\"value\":99794944},\"jvm.memory.pools.Metaspace.init\":{\"value\":0},\"jvm.memory.pools.Metaspace.max\":{\"value\":375390208},\"jvm.memory.pools.Metaspace.usage\":{\"value\":0.25168142904782426},\"jvm.memory.pools.Metaspace.used\":{\"value\":94478744},\"jvm.memory.pools.PS-Eden-Space.committed\":{\"value\":349700096},\"jvm.memory.pools.PS-Eden-Space.init\":{\"value\":422576128},\"jvm.memory.pools.PS-Eden-Space.max\":{\"value\":1110966272},\"jvm.memory.pools.PS-Eden-Space.usage\":{\"value\":0.07505125052077188},\"jvm.memory.pools.PS-Eden-Space.used\":{\"value\":83379408},\"jvm.memory.pools.PS-Eden-Space.used-after-gc\":{\"value\":0},\"jvm.memory.pools.PS-Old-Gen.committed\":{\"value\":1127219200},\"jvm.memory.pools.PS-Old-Gen.init\":{\"value\":1127219200},\"jvm.memory.pools.PS-Old-Gen.max\":{\"value\":2253914112},\"jvm.memory.pools.PS-Old-Gen.usage\":{\"value\":0.014950035505168354},\"jvm.memory.pools.PS-Old-Gen.used\":{\"value\":33696096},\"jvm.memory.pools.PS-Old-Gen.used-after-gc\":{\"value\":23791152},\"jvm.memory.pools.PS-Survivor-Space.committed\":{\"value\":1048576},\"jvm.memory.pools.PS-Survivor-Space.init\":{\"value\":70254592},\"jvm.memory.pools.PS-Survivor-Space.max\":{\"value\":1048576},\"jvm.memory.pools.PS-Survivor-Space.usage\":{\"value\":0.59375},\"jvm.memory.pools.PS-Survivor-Space.used\":{\"value\":622592},\"jvm.memory.pools.PS-Survivor-Space.used-after-gc\":{\"value\":622592},\"jvm.memory.total.committed\":{\"value\":1644412928},\"jvm.memory.total.init\":{\"value\":1697972224},\"jvm.memory.total.max\":{\"value\":3999268864},\"jvm.memory.total.used\":{\"value\":269184904},\"jvm.thread.blocked.count\":{\"value\":0},\"jvm.thread.count\":{\"value\":82},\"jvm.thread.daemon.count\":{\"value\":11},\"jvm.thread.deadlock.count\":{\"value\":0},\"jvm.thread.deadlocks\":{\"value\":[]},\"jvm.thread.new.count\":{\"value\":0},\"jvm.thread.runnable.count\":{\"value\":25},\"jvm.thread.terminated.count\":{\"value\":0},\"jvm.thread.timed_waiting.count\":{\"value\":10},\"jvm.thread.waiting.count\":{\"value\":47}},\"counters\":{},\"histograms\":{},\"meters\":{},\"timers\":{}}\n\n$ curl -H 'Accept: application/prometheus' http://otoroshi-api.oto.tools:8080/metrics\\?access_key\\=MILpkVv6f2kG9Xmnc4mFIYRU4rTxHVGkxvB0hkQLZwEaZgE2hgbOXiRsN1DBnbtY\n# TYPE attr_jvm_cpu_usage gauge\nattr_jvm_cpu_usage 83.0\n# TYPE attr_jvm_heap_size gauge\nattr_jvm_heap_size 1409.0\n# TYPE attr_jvm_heap_used gauge\nattr_jvm_heap_used 220.0\n# TYPE internals_0_concurrent_requests gauge\ninternals_0_concurrent_requests 1.0\n# TYPE internals_global_throttling_quotas gauge\ninternals_global_throttling_quotas 3.0\n# TYPE jvm_attr_uptime gauge\njvm_attr_uptime 2372614.0\n# TYPE jvm_gc_PS_MarkSweep_count gauge\njvm_gc_PS_MarkSweep_count 3.0\n# TYPE jvm_gc_PS_MarkSweep_time gauge\njvm_gc_PS_MarkSweep_time 261.0\n# TYPE jvm_gc_PS_Scavenge_count gauge\njvm_gc_PS_Scavenge_count 12.0\n# TYPE jvm_gc_PS_Scavenge_time gauge\njvm_gc_PS_Scavenge_time 161.0\n# TYPE jvm_memory_heap_committed gauge\njvm_memory_heap_committed 1.477967872E9\n# TYPE jvm_memory_heap_init gauge\njvm_memory_heap_init 1.690304512E9\n# TYPE jvm_memory_heap_max gauge\njvm_memory_heap_max 3.005218816E9\n# TYPE jvm_memory_heap_usage gauge\njvm_memory_heap_usage 0.07680553268571043\n# TYPE jvm_memory_heap_used gauge\njvm_memory_heap_used 2.30817432E8\n# TYPE jvm_memory_non_heap_committed gauge\njvm_memory_non_heap_committed 1.66510592E8\n# TYPE jvm_memory_non_heap_init gauge\njvm_memory_non_heap_init 7667712.0\n# TYPE jvm_memory_non_heap_max gauge\njvm_memory_non_heap_max 9.94050048E8\n# TYPE jvm_memory_non_heap_usage gauge\njvm_memory_non_heap_usage 0.15262878997416435\n# TYPE jvm_memory_non_heap_used gauge\njvm_memory_non_heap_used 1.51720656E8\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__committed gauge\njvm_memory_pools_CodeHeap__non_nmethods__committed 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__init gauge\njvm_memory_pools_CodeHeap__non_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__max gauge\njvm_memory_pools_CodeHeap__non_nmethods__max 5832704.0\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__usage gauge\njvm_memory_pools_CodeHeap__non_nmethods__usage 0.28408093398876405\n# TYPE jvm_memory_pools_CodeHeap__non_nmethods__used gauge\njvm_memory_pools_CodeHeap__non_nmethods__used 1656960.0\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__committed gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__committed 1.1862016E7\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__init gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__max gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__max 1.22912768E8\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__usage gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__usage 0.09610562183417755\n# TYPE jvm_memory_pools_CodeHeap__non_profiled_nmethods__used gauge\njvm_memory_pools_CodeHeap__non_profiled_nmethods__used 1.1812608E7\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__committed gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__committed 3.735552E7\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__init gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__init 2555904.0\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__max gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__max 1.22912768E8\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__usage gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__usage 0.25493618368435084\n# TYPE jvm_memory_pools_CodeHeap__profiled_nmethods__used gauge\njvm_memory_pools_CodeHeap__profiled_nmethods__used 3.1334912E7\n# TYPE jvm_memory_pools_Compressed_Class_Space_committed gauge\njvm_memory_pools_Compressed_Class_Space_committed 1.4942208E7\n# TYPE jvm_memory_pools_Compressed_Class_Space_init gauge\njvm_memory_pools_Compressed_Class_Space_init 0.0\n# TYPE jvm_memory_pools_Compressed_Class_Space_max gauge\njvm_memory_pools_Compressed_Class_Space_max 3.670016E8\n# TYPE jvm_memory_pools_Compressed_Class_Space_usage gauge\njvm_memory_pools_Compressed_Class_Space_usage 0.03386023385184152\n# TYPE jvm_memory_pools_Compressed_Class_Space_used gauge\njvm_memory_pools_Compressed_Class_Space_used 1.242676E7\n# TYPE jvm_memory_pools_Metaspace_committed gauge\njvm_memory_pools_Metaspace_committed 9.9794944E7\n# TYPE jvm_memory_pools_Metaspace_init gauge\njvm_memory_pools_Metaspace_init 0.0\n# TYPE jvm_memory_pools_Metaspace_max gauge\njvm_memory_pools_Metaspace_max 3.75390208E8\n# TYPE jvm_memory_pools_Metaspace_usage gauge\njvm_memory_pools_Metaspace_usage 0.25170985813247426\n# TYPE jvm_memory_pools_Metaspace_used gauge\njvm_memory_pools_Metaspace_used 9.4489416E7\n# TYPE jvm_memory_pools_PS_Eden_Space_committed gauge\njvm_memory_pools_PS_Eden_Space_committed 3.49700096E8\n# TYPE jvm_memory_pools_PS_Eden_Space_init gauge\njvm_memory_pools_PS_Eden_Space_init 4.22576128E8\n# TYPE jvm_memory_pools_PS_Eden_Space_max gauge\njvm_memory_pools_PS_Eden_Space_max 1.110966272E9\n# TYPE jvm_memory_pools_PS_Eden_Space_usage gauge\njvm_memory_pools_PS_Eden_Space_usage 0.17698545577448457\n# TYPE jvm_memory_pools_PS_Eden_Space_used gauge\njvm_memory_pools_PS_Eden_Space_used 1.96624872E8\n# TYPE jvm_memory_pools_PS_Eden_Space_used_after_gc gauge\njvm_memory_pools_PS_Eden_Space_used_after_gc 0.0\n# TYPE jvm_memory_pools_PS_Old_Gen_committed gauge\njvm_memory_pools_PS_Old_Gen_committed 1.1272192E9\n# TYPE jvm_memory_pools_PS_Old_Gen_init gauge\njvm_memory_pools_PS_Old_Gen_init 1.1272192E9\n# TYPE jvm_memory_pools_PS_Old_Gen_max gauge\njvm_memory_pools_PS_Old_Gen_max 2.253914112E9\n# TYPE jvm_memory_pools_PS_Old_Gen_usage gauge\njvm_memory_pools_PS_Old_Gen_usage 0.014950035505168354\n# TYPE jvm_memory_pools_PS_Old_Gen_used gauge\njvm_memory_pools_PS_Old_Gen_used 3.3696096E7\n# TYPE jvm_memory_pools_PS_Old_Gen_used_after_gc gauge\njvm_memory_pools_PS_Old_Gen_used_after_gc 2.3791152E7\n# TYPE jvm_memory_pools_PS_Survivor_Space_committed gauge\njvm_memory_pools_PS_Survivor_Space_committed 1048576.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_init gauge\njvm_memory_pools_PS_Survivor_Space_init 7.0254592E7\n# TYPE jvm_memory_pools_PS_Survivor_Space_max gauge\njvm_memory_pools_PS_Survivor_Space_max 1048576.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_usage gauge\njvm_memory_pools_PS_Survivor_Space_usage 0.59375\n# TYPE jvm_memory_pools_PS_Survivor_Space_used gauge\njvm_memory_pools_PS_Survivor_Space_used 622592.0\n# TYPE jvm_memory_pools_PS_Survivor_Space_used_after_gc gauge\njvm_memory_pools_PS_Survivor_Space_used_after_gc 622592.0\n# TYPE jvm_memory_total_committed gauge\njvm_memory_total_committed 1.644478464E9\n# TYPE jvm_memory_total_init gauge\njvm_memory_total_init 1.697972224E9\n# TYPE jvm_memory_total_max gauge\njvm_memory_total_max 3.999268864E9\n# TYPE jvm_memory_total_used gauge\njvm_memory_total_used 3.82665128E8\n# TYPE jvm_thread_blocked_count gauge\njvm_thread_blocked_count 0.0\n# TYPE jvm_thread_count gauge\njvm_thread_count 82.0\n# TYPE jvm_thread_daemon_count gauge\njvm_thread_daemon_count 11.0\n# TYPE jvm_thread_deadlock_count gauge\njvm_thread_deadlock_count 0.0\n# TYPE jvm_thread_new_count gauge\njvm_thread_new_count 0.0\n# TYPE jvm_thread_runnable_count gauge\njvm_thread_runnable_count 25.0\n# TYPE jvm_thread_terminated_count gauge\njvm_thread_terminated_count 0.0\n# TYPE jvm_thread_timed_waiting_count gauge\njvm_thread_timed_waiting_count 10.0\n# TYPE jvm_thread_waiting_count gauge\njvm_thread_waiting_count 47.0\n```"},{"name":"otoroshi-protocol.md","id":"/topics/otoroshi-protocol.md","url":"/topics/otoroshi-protocol.html","title":"The Otoroshi communication protocol","content":"# The Otoroshi communication protocol\n\nThe exchange protocol secure the communication with an app. When it's enabled, Otoroshi will send for each request a value in pre-selected token header, and will check the same header in the return request.\n\n### V1 challenge\n\nIf you enable secure communication for a given service with `V1 - simple values exchange` activated, you will have to add a filter on the target application that will take the `Otoroshi-State` header and return it in a header named `Otoroshi-State-Resp`. \n\n@@@ div { .centered-img }\n\n@@@\n\nyou can find an example project that implements V1 challenge [here](https://github.com/MAIF/otoroshi/tree/master/demos/challenge)\n\n### V2 challenge\n\nIf you enable secure communication for a given service with `V2 - signed JWT token exhange` activated, you will have to add a filter on the target application that will take the `Otoroshi-State` header value containing a JWT token, verify it's content signature then extract a claim named `state` and return a new JWT token in a header named `Otoroshi-State-Resp` with the `state` value in a claim named `state-resp`. By default, the signature algorithm is HMAC+SHA512 but can you can choose your own. The sent and returned JWT tokens have short TTL to avoid being replayed. You must be validate the tokens TTL. The audience of the response token must be `Otoroshi` and you have to specify `iat`, `nbf` and `exp`.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can find an example project that implements V2 challenge [here](https://github.com/MAIF/otoroshi/tree/master/demos/challenge)\n\n### Info. token\n\nOtoroshi is also sending a JWT token in a header named `Otoroshi-Claim` that the target app can validate too.\n\nThe `Otoroshi-Claim` is a JWT token containing some informations about the service that is called and the client if available. You can choose between a legacy version of the token and a new one that is more clear and structured.\n\nBy default, the otoroshi jwt token is signed with the `otoroshi.claim.sharedKey` config property (or using the `$CLAIM_SHAREDKEY` env. variable) and uses the `HMAC512` signing algorythm. But it is possible to customize how the token is signed from the service descriptor page in the `Otoroshi exchange protocol` section. \n\n@@@ div { .centered-img }\n\n@@@\n\nusing another signing algo.\n\n@@@ div { .centered-img }\n\n@@@\n\nhere you can choose the signing algorithm and the secret/keys used. You can use syntax like `${env.MY_ENV_VAR}` or `${config.my.config.path}` to provide secret/keys values. \n\nFor example, for a service named `my-service` with a signing key `secret` with `HMAC512` signing algorythm, the basic JWT token that will be sent should look like the following\n\n```\neyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiItLSIsImF1ZCI6Im15LXNlcnZpY2UiLCJpc3MiOiJPdG9yb3NoaSIsImV4cCI6MTUyMTQ0OTkwNiwiaWF0IjoxNTIxNDQ5ODc2LCJqdGkiOiI3MTAyNWNjMTktMmFjNy00Yjk3LTljYzctMWM0ODEzYmM1OTI0In0.mRcfuFVFPLUV1FWHyL6rLHIJIu0KEpBkKQCk5xh-_cBt9cb6uD6enynDU0H1X2VpW5-bFxWCy4U4V78CbAQv4g\n```\n\nif you decode it, the payload will look something like\n\n```json\n{\n \"sub\": \"apikey_client_id\",\n \"aud\": \"my-service\",\n \"iss\": \"Otoroshi\",\n \"exp\": 1521449906,\n \"iat\": 1521449876,\n \"jti\": \"71025cc19-2ac7-4b97-9cc7-1c4813bc5924\"\n}\n```\n\nIf you want to validate the `Otoroshi-Claim` on the target app side to ensure that the input requests only comes from `Otoroshi`, you will have to write an HTTP filter to do the job. For instance, if you want to write a filter to make sure that requests only comes from Otoroshi, you can write something like the following (using playframework 2.6).\n\nScala\n: @@snip [filter.scala](../snippets/filter.scala)\n\nJava\n: @@snip [filter.java](../snippets/filter.java)\n"},{"name":"pki.md","id":"/topics/pki.md","url":"/topics/pki.html","title":"Otoroshi's PKI","content":"# Otoroshi's PKI\n\nWith Otoroshi, you can add your own certificates, your own CA and even create self signed certificates or certificates from CAs. You can enable auto renewal of thoses self signed certificates or certificates generated. Certificates have to be created with the certificate chain and the private key in PEM format.\n\nAn Otoroshi instance always starts with 5 auto-generated certificates. \n\nThe highest certificate is the **Otoroshi Default Root CA Certificate**. This certificate is used by Otoroshi to sign the intermediate CA.\n\n**Otoroshi Default Intermediate CA Certificate**: first intermediate CA that must be used to issue new certificates in Otoroshi. Creating certificates directly from the CA root certificate increases the risk of root certificate compromise, and if the CA root certificate is compromised, the entire trust infrastructure built by the SSL provider will fail\n\nThis intermediate CA signed three certificates :\n\n* **Otoroshi Default Client certificate**: \n* **Otoroshi Default Jwt Signing Keypair**: default keypair (composed of a public and private key), exposed on `https://xxxxxx/.well-known/jwks.json`, that can be used to sign and verify JWT verifier\n* **Otoroshi Default Wildcard Certificate**: this certificate has `*.oto.tools` as common name. It can be very useful to the development phase\n\n## The PKI API\n\nThe Otoroshi's PKI can be managed using the admin api of otoroshi (by default admin api is exposed on https://otoroshi-api.xxxxx)\n\nLink to the complete swagger section about PKI : https://maif.github.io/otoroshi/swagger-ui/index.html#/pki\n\n* `POST` [/api/pki/certs/_letencrypt](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genLetsEncryptCert): generates a certificate using Let's Encrypt or any ACME compatible system\n* `POST` [/api/pki/certs/_p12](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.importCertFromP12): import a .p12 file as client certificates\n* `POST` [/api/pki/certs/_valid](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.certificateIsValid): check if a certificate is valid (based on its own data)\n* `POST` [/api/pki/certs/_data](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.certificateData): extract data from a certificate\n* `POST` [/api/pki/certs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSelfSignedCert): generates a self signed certificates\n* `POST` [/api/pki/csrs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genCsr) : generates a CSR\n* `POST` [/api/pki/keys](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genKeyPair) : generates a keypair\n* `POST` [/api/pki/cas](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSelfSignedCA) : generates a self signed CA\n* `POST` [/api/pki/cas/:ca/certs/_sign](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.signCert): sign a certificate based on CSR\n* `POST` [/api/pki/cas/:ca/certs](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genCert): generates a certificate\n* `POST` [/api/pki/cas/:ca/cas](https://maif.github.io/otoroshi/swagger-ui/index.html#/pki/otoroshi.controllers.adminapi.PkiController.genSubCA) : generates a sub-CA\n\n## The PKI UI\n\nAll generated certificates are listed in the `https://xxxxxx/bo/dashboard/certificates` page. All those certificates can be used to serve traffic with TLS, perform mTLS calls, sign and verify JWT tokens.\n\nThe PKI UI are composed of these following actions:\n\n* **Add item**: redirects the user on the certificate creation page. It’s useful when you already had a certificate (like a pem file) and that you want to load it in Otoroshi.\n* **Let's Encrypt certificate**: asks a certificate matching a given host to Let’s encrypt\n* **Create certificate**: issues a certificate with an existing Otoroshi certificate as CA. You can create a client certificate, a server certificate or a keypair certiciate that will be used to verify and sign JWT tokens.\n* **Import .p12 file**: loads a p12 file as certificate\n\nUnder these buttons, you have the list of current certificates, imported or generated, revoked or not. For each certificate, you will find: \n\n* a **name** \n* a **description** \n* the **subject** \n* the **type** of certificate (CA / client / keypair / certificate)\n* the **revoked reason** (empty if not) \n* the **creation date** following by its **expiration date**.\n\n## Exposed public keys\n\nThe Otoroshi certificate can be turned and used as keypair (simple action that can be executed by editing a certificate or during its creation, or using the admin api). A Otoroski keypair can be used to sign and verify JWT tokens with asymetric signature. Once a jwt token is signed with a keypair, it can be necessary to provide a way to the services to verify the tokens received by Otoroshi. This usage is cover by Otoroshi by the flag `Public key exposed`, available on each certificate.\n\nOtoroshi exposes each keypair with the flag enabled, on the following routes:\n\n* `https://xxxxxxxxx.xxxxxxx.xx/.well-known/otoroshi/security/jwks.json`\n* `https://otoroshi-api.xxxxxxx.xx/.well-known/jwks.json`\n\nOn these routes, you will find the list of public keys exposed using [the JWK standard](https://datatracker.ietf.org/doc/html/rfc7517)\n\n\n## OCSP Responder\n\nOtoroshi is able to revocate a certificate, directly from the UI, and to add a revocation status to specifiy the reason. The revocation reason can be :\n\n* `VALID`: The certificate is not revoked\n* `UNSPECIFIED`: Can be used to revoke certificates for reasons other than the specific codes.\n* `KEY_COMPROMISE`: It is known or suspected that the subject's private key or other aspects have been compromised.\n* `CA_COMPROMISE`: It is known or suspected that the subject's private key or other aspects have been compromised.\n* `AFFILIATION_CHANGED`: The subject's name or other information in the certificate has been modified but there is no cause to suspect that the private key has been compromised.\n* `SUPERSEDED`: The certificate has been superseded but there is no cause to suspect that the private key has been compromised\n* `CESSATION_OF_OPERATION`: The certificate is no longer needed for the purpose for which it was issued but there is no cause to suspect that the private key has been compromised\n* `CERTIFICATE_HOLD`: The certificate is temporarily revoked but there is no cause to suspect that the private kye has been compromised\n* `REMOVE_FROM_CRL`: The certificate has been unrevoked\n* `PRIVILEGE_WITH_DRAWN`: The certificate was revoked because a privilege contained within that certificate has been withdrawn\n* `AA_COMPROMISE`: It is known or suspected that aspects of the AA validated in the attribute certificate, have been compromised\n\nOtoroshi supports the Online Certificate Status Protocol for obtaining the revocation status of its certificates. The OCSP endpoint is also add to any generated certificate. This endpoint is available at `https://otoroshi-api.xxxxxx/.well-known/otoroshi/security/ocsp`\n\n## A.I.A : Authority Information Access\n\nOtoroshi provides a way to add the A.I.A in the certificate. This certificate extension contains :\n\n* Information about how to get the issuer of this certificate (CA issuer access method)\n* Address of the OCSP responder from where revocation of this certificate can be checked (OCSP access method)\n\n`https://xxxxxxxxxx/.well-known/otoroshi/security/certificates/:cert-id`"},{"name":"sessions-mgmt.md","id":"/topics/sessions-mgmt.md","url":"/topics/sessions-mgmt.html","title":"Sessions management","content":"# Sessions management\n\n## Admins\n\nAll logged users to an Otoroshi instance are administrators. An user session is created for each sucessfull connection to the UI. \n\nThese sessions are listed in the `Admin users sessions` (available in the cog icon menu or at this location of your instance `/bo/dashboard/sessions/admin`).\n\nAn admin user session is composed of: \n\n* `name`: the name of the connected user\n* `email`: the unique email\n* `Created at`: the creation date of the user session\n* `Expires at`: date until the user session is drop\n* `Profile`: user profile, at JSON format, containing name, email and others linked metadatas\n* `Rights`: list of rules to authorize the connected user on each tenant and teams.\n* `Discard session`: action to kill a session. On click, a modal will appear with the session ID\n\nIn the `Admin users sessions` page, you have two more actions:\n\n* `Discard all sessions`: kills all current sessions (including the session of the owner of this action)\n* `Discard old sessions`: kill all outdated sessions\n\n## Private apps\n\nAll logged users to a protected application has an private user session.\n\nThese sessions are listed in the `Private apps users sessions` (available in the cog icon menu or at this location of your instance `/bo/dashboard/sessions/private`).\n\nAn private user session is composed of: \n\n* `name`: the name of the connected user\n* `email`: the unique email\n* `Created at`: the creation date of the user session\n* `Expires at`: date until the user session is drop\n* `Profile`: user profile, at JSON format, containing name, email and others linked metadatas\n* `Meta.`: list of metadatas added by the authentication module.\n* `Tokens`: list of tokens received from the identity provider used. In the case of a memory authentication, this part will keep empty.\n* `Discard session`: action to kill a session. On click, a modal will appear with the session ID\n"},{"name":"tls.md","id":"/topics/tls.md","url":"/topics/tls.html","title":"TLS","content":"# TLS\n\nas you might have understand, otoroshi can store TLS certificates and use them dynamically. It means that once a certificate is imported or created in otoroshi, you can immediately use it to serve http request over TLS, to call https backends that requires mTLS or that do not have certicates signed by a globally knowned authority.\n\n## TLS termination\n\nany certficate added to otoroshi with a valid `CN` and `SANs` can be used in the following seconds to serve https requests. If you do not provide a private key with a certificate chain, the certificate will only be trusted like a CA. If you want to perform mTLS calls on you otoroshi instance, do not forget to enabled it (it is disabled by default for performance reasons as the TLS handshake is bigger with mTLS enabled)\n\n```sh\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```sh\nSSL_OUTSIDE_CLIENT_AUTH=None|Want|Need\n```\n\n### TLS termination configuration\n\nYou can configure TLS termination statically using config. file or env. variables. Everything is available at `otoroshi.tls`\n\n```conf\notoroshi {\n tls {\n # the cipher suites used by otoroshi TLS termination\n cipherSuitesJDK11 = [\"TLS_AES_128_GCM_SHA256\", \"TLS_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_RSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_RSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA\", \"TLS_EMPTY_RENEGOTIATION_INFO_SCSV\"]\n cipherSuitesJDK8 = [\"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_RSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_256_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_256_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256\", \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_RSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA\", \"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_RSA_WITH_AES_128_CBC_SHA\", \"TLS_DHE_DSS_WITH_AES_128_CBC_SHA\", \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256\", \"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256\", \"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256\", \"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_RSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA\", \"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA\", \"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA\", \"TLS_EMPTY_RENEGOTIATION_INFO_SCSV\"]\n cipherSuites = []\n # the protocols used by otoroshi TLS termination\n protocolsJDK11 = [\"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\"]\n protocolsJDK8 = [\"SSLv2Hello\", \"TLSv1\", \"TLSv1.1\", \"TLSv1.2\"]\n protocols = []\n # the JDK cacert access\n cacert {\n path = \"$JAVA_HOME/lib/security/cacerts\"\n password = \"changeit\"\n }\n # the mtls mode\n fromOutside {\n clientAuth = \"None\"\n clientAuth = ${?SSL_OUTSIDE_CLIENT_AUTH}\n }\n # the default trust mode\n trust {\n all = false\n all = ${?OTOROSHI_SSL_TRUST_ALL}\n }\n # some initial cacert access, useful to include non standard CA when starting (file paths)\n initialCacert = ${?CLUSTER_WORKER_INITIAL_CACERT}\n initialCacert = ${?INITIAL_CACERT}\n initialCert = ${?CLUSTER_WORKER_INITIAL_CERT}\n initialCert = ${?INITIAL_CERT}\n initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY}\n initialCertKey = ${?INITIAL_CERT_KEY}\n # initialCerts = [] \n }\n}\n```\n\n\n### TLS termination settings\n\nIt is possible to adjust the behavior of the TLS termination from the `danger zone` at the `Tls Settings` section. Here you can either define that a non-matching SNI call will use a random TLS certtificate to reply or will use a default domain (the TLS certificate associated to this domain) to reply. Here you can also choose if you want to trust all the CAs trusted by your JDK when performing TLS calls `Trust JDK CAs (client)` or when receiving mTLS calls `Trust JDK CAs (server)`. If you disable the later, it is possible to select the list of CAs presented to the client during mTLS handshake.\n\n### Certificates auto generation\n\nit is also possible to generate non-existing certificate on the fly without losing the request. If you are interested by this feature, you can enable it in the `danger zone` at the `Auto Generate Certificates` section. Here you'll have to enable it and select the CA that will generate the certificate. Of course, the client will have to trust the selected CA. You can also add filters to choose which domain are allowed to generate certificates or not. The `Reply Nicely` flag is used to reply a nice error message (ie. human readable) telling that it's not possible to have an auto certficate for the current domain. \n\n## Backends TLS and mTLS calls\n\nFor any call to a backend, it is possible to customize the TLS behavior \n\n@@@ div { .centered-img }\n\n@@@\n\nhere you can define your level of trust (trust all, loose verification) or even select on or more CAs you will trust for the following backend calls. You can also select the client certificate that will be used for the following backend calls\n\n## Keypair for signing and verification\n\nIt is also possible to use the keypair contained in a certificate to sign and verificate JWT token signature. You can mark an existing certificate in otoroshi as a keypair using the `keypair` on the certificate page.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"user-rights.md","id":"/topics/user-rights.md","url":"/topics/user-rights.html","title":"Otoroshi user rights","content":"# Otoroshi user rights\n\nIn Otoroshi, all users are considered **Administrators**. This choice is reinforced by the fact that Otoroshi is designed to be an administrator user interface and not an interface for users who simply want to view information. For this type of use, we encourage to use the admin API rather than giving access to the user interface.\n\nThe Otoroshi rights are split by a list of authorizations on **organizations** and **teams**. \n\nLet's taking an example where we want to authorize an administrator user on all organizations and teams.\n\nThe list of rights will be :\n\n```json\n[\n {\n \"tenant\": \"*:rw\", # (1)\n \"teams\": [\"*:rw\"] # (2)\n }\n]\n```\n\n* (1): this field, separated by a colon, indicates the name of the tenant and the associated rights. In our case, we set `*` to apply the rights to all tenants, and the `rw` to get the read and write access on them.\n* (2): the `teams` array field, represents the list of rights, applied by team. The behaviour is the same as the tenant field, we define the team or the wildcard, followed by the rights\n\nif you want to have an user that is administrator only for one organization, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\"*:rw\"]\n }\n]\n```\n\nif you want to have an user that is administrator only for two organization, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\"*:rw\"]\n },\n {\n \"tenant\": \"orga-2:rw\",\n \"teams\": [\"*:rw\"]\n }\n]\n```\n\nif you want to have an user that can only see 3 teams of one organization and one team in the other, the rights will be :\n\n```json\n[\n {\n \"tenant\": \"orga-1:rw\",\n \"teams\": [\n \"team-1:rw\",\n \"team-2:rw\",\n \"team-3:rw\",\n ]\n },\n {\n \"tenant\": \"orga-2:rw\",\n \"teams\": [\n \"team-4:rw\"\n ]\n }\n]\n```\n\nThe list of possible rights for an organization or a team is:\n\n* **r**: read access\n* **w**: write access\n* **not**: none access to the resource\n\nThe list of possible tenant and teams are your created tenants and teams, and the wildcard to define rights to all resources once.\n\nThe user rights is defined by the @ref:[authentication modules](../entities/auth-modules.md).\n"}] \ No newline at end of file diff --git a/docs/manual/css/fonts/icons.eot b/docs/manual/css/fonts/icons.eot deleted file mode 100644 index a5203e8766..0000000000 Binary files a/docs/manual/css/fonts/icons.eot and /dev/null differ diff --git a/docs/manual/css/fonts/icons.svg b/docs/manual/css/fonts/icons.svg deleted file mode 100644 index 58c7488236..0000000000 --- a/docs/manual/css/fonts/icons.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - -Generated by Fontastic.me - - - - - - - - diff --git a/docs/manual/css/fonts/icons.ttf b/docs/manual/css/fonts/icons.ttf deleted file mode 100644 index 6da4b13e05..0000000000 Binary files a/docs/manual/css/fonts/icons.ttf and /dev/null differ diff --git a/docs/manual/css/fonts/icons.woff b/docs/manual/css/fonts/icons.woff deleted file mode 100644 index 2c7e917bb9..0000000000 Binary files a/docs/manual/css/fonts/icons.woff and /dev/null differ diff --git a/docs/manual/css/page.css b/docs/manual/css/page.css deleted file mode 100644 index 7bd5e1b71e..0000000000 --- a/docs/manual/css/page.css +++ /dev/null @@ -1,1182 +0,0 @@ -@charset "UTF-8"; - -/* fonts */ - -@font-face { - font-family: "icons"; - src:url("fonts/icons.eot"); - src:url("fonts/icons.eot?#iefix") format("embedded-opentype"), - url("fonts/icons.woff") format("woff"), - url("fonts/icons.ttf") format("truetype"), - url("fonts/icons.svg#icons") format("svg"); - font-weight: normal; - font-style: normal; -} - -/* body */ - -body { - background: #fff; - padding: 0; - margin: 0; - font-weight: 400; - font-style: normal; - line-height: 1.4em; - position: relative; - cursor: default; - font: 1em "Roboto", "Helvetica Neue", "Helvetica", Arial, sans-serif; - color: #333333; - font-smoothing: antialiased; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-font-size-adjust: none; - text-rendering: optimizeLegibility; -} - -/* headers */ - -h1 { - font-family: inherit; - font-size: 2.6em; - font-weight: 300; - color: #333333; - margin-bottom: 0.4em; - margin-top: 1.1em; -} - -h1:first-child { - margin-top: 0; -} - -h2 { - font-family: inherit; - font-size: 1.8em; - font-weight: 400; - color: #333333; - margin-bottom: 0.2em; - margin-top: 1.3em; -} - -h2:first-child { - margin-top: 0; -} - -h3 { - font-family: inherit; - font-size: 1.125em; - font-weight: 700; - color: #333333; - margin-top: 1.3em; -} - -h3:first-child { - margin-top: 0; -} - -h4 { - font-family: inherit; - font-size: 1em; - font-weight: 700; - color: #333333; - margin-top: 1.3em; -} - -h4:first-child { - margin-top: 0; -} - -h5 { - font-family: inherit; - font-size: 1em; - color: #333333; - margin-top: 1.3em; -} - -h5:first-child { - margin-top: 0; -} - -h6 { - font-family: inherit; - font-size: 1em; - color: #333333; - margin-top: 1.3em; -} - -h6:first-child { - margin-top: 0; -} - -/* text */ - -p { - font-family: inherit; - font-size: 1em; - color: #333333; - line-height: 1.45em; - margin: 1em 0em; -} - -/* links */ - -a { - font-family: inherit; - color: #4078c0; - text-decoration: none; - cursor: pointer; -} - -a:link { - color: #4078c0; -} - -a:visited { - color: #4078c0; -} - -a:hover { - color: #4078c0; - text-decoration: underline; -} - -a:active { - color: #4078c0; -} - -/* header anchors */ - -a.anchor .anchor-link:before { - content: "§"; - font-size: 18px; - font-family: "icons" !important; - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1.2; - vertical-align: middle; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { - visibility: hidden; - position: absolute; - display: block; - width: 30px; - margin-left: -30px; - padding-right: 3px; - text-align: right; - text-decoration: none; -} - -h1:hover > a.anchor, h2:hover > a.anchor, h3:hover > a.anchor, h4:hover > a.anchor, h5:hover > a.anchor, h6:hover > a.anchor { - visibility: visible; - color: inherit; - text-decoration: none; -} - - -/* table */ - -table th { - background: #ffffff; - border: solid 1px #dddddd; -} - -table td { - background: #ffffff; - border: solid 1px #dddddd; -} - -/* code */ - -pre { - padding: 1rem !important; - border: 1px solid #dddddd !important; - margin: 0 0 1rem 0 !important; - white-space: pre; - overflow: auto; - line-height: 0.9em !important; - border-radius: 4px; -} - -code { - line-height: 1.45em !important; - font-family: Consolas, "Liberation Mono", Courier, monospace; - font-size: 0.85em !important; - font-weight: normal !important; - padding: 0 !important; -} - -pre > code { - background: none; - border: none; -} - -p code { - border: none; - color: #0c323b; - padding: 0 0.2em !important; -} - -li code { - border: none; - color: #0c323b; - padding: 0 0.2em !important; -} - -/* Github-like */ - -pre.prettyprint span.str { - color: #183691; -} -pre.prettyprint span.kwd { - color: #000000; - font-weight: bold; -} -pre.prettyprint span.com { - color: #999988; - font-style: italic; -} -pre.prettyprint span.typ { - color: #445588; - font-weight: bold; -} -pre.prettyprint span.lit { - color: #009999 -} -pre.prettyprint span.pun { - color: #000000; - font-weight: bold; -} -pre.prettyprint span.pln { - color: #000000 -} -pre.prettyprint span.tag { - color: navy -} -pre.prettyprint span.atn { - color: teal -} -pre.prettyprint span.atv { - color: #dd1144 -} -pre.prettyprint span.dec { - color: #990000 -} -pre.prettyprint span.var { - color: #000000 -} -pre.prettyprint span.fun { - color: #990000 -} - -/* tabbed code snippets */ - -dl.tabbed { - position: relative; -} - -dl.tabbed dt { - float: left; - display: inline-block; - position: relative; - left: 1px; - margin-left: -1px; -} - -dl.tabbed dt.current { - z-index: 2; -} - -dl.tabbed dt a { - display: block; - border: 1px solid #f7f7f7; - padding: 0 20px; - height: 30px; - line-height: 2; - color: #4078c0; - text-decoration: none; -} - -dl.tabbed dt a:hover { - background: #f7f7f7; -} - -dl.tabbed dt.first a { - border-top-left-radius: 5px; -} - -dl.tabbed dt.last a { - border-top-right-radius: 5px; -} - -dl.tabbed dt.current a { - background-color: #f7f7f7; - border-color: #dddddd; - border-bottom: 0; - padding-bottom: 1px; -} - -dl.tabbed dt.current a { - color: #0c323b; - outline: none; -} - -dl.tabbed dd { - position: absolute; - width: 100%; - left: 0; - top: 29px; -} - -dl.tabbed dd.current { - z-index: 1; -} - -dl.tabbed dd pre { - border-top-left-radius: 0 !important; -} - -dl.tabbed dd.has-note pre { - border-bottom: 0 !important; - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; - margin-bottom: 0 !important; -} - -dl.tabbed dd.has-note blockquote { - color: #0c323b; - border: solid #dddddd; - border-width: 1px 1px 1px 10px; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - margin-top: 0; - font-style: italic; -} - -/* blockquotes */ - -blockquote { - border-left: 4px solid rgb(221, 221, 221); - margin: 1.5em 0; - padding: 1em 20px; - color: rgb(119, 119, 119); - line-height: 1.4em; -} - -blockquote p { - margin: 0; - line-height: 1.4em; -} - -blockquote p ~ p { - margin-top: 1em; -} - -blockquote p code { - background: #fff; - padding-right: 0.4em !important; -} - -/* callout */ - -.callout { - border: none; - border-left: 10px solid #4078c0; - background-color: rgba(64, 120, 192, 0.1); -} - -.callout.warning { - border-color: #DB504A; - background-color: #fff3d9; -} - -.callout .callout-title { - font-weight: bold; - margin-bottom: 0.33em; -} - -.callout div ~ p { - margin-top: 0; -} - -.callout p ~ p { - margin-top: 1em; - margin-bottom: 0; -} - -.callout p code { - background: #fff; - padding-right: 0.4em !important; -} - -/* footnotes */ - -small { - display: block; -} - -/* logo links */ - -.logo .svg-icon-logo { - height: 24px; - width: 112px; -} - -.logo:hover { - text-decoration: none; -} - -.svg-icon-logo .svg-icon-logo-text { - fill: #ffffff; -} - -.logo:hover .svg-icon-logo .svg-icon-logo-text { - fill: #4078C0; -} - -/* site header */ - -.site-header { - background: #fcfcfc; - border-bottom: solid 1px #cccccc; -} - -.site-header .title { - display: inline-block; - float: left; - height: 70px; - line-height: 70px; - font-weight: 400; - font-size: 1.4em; -} - -.site-header .title a:link, .site-header .title a:visited { - color: #515151; -} - -.site-header .title a:hover { - color: #515151; - text-decoration: none; -} - -.site-header .off-canvas-toggle { - float: left; -} - -.site-header .off-canvas-toggle .svg-icon-menu { - height: 40px; - width: 40px; - margin-top: 1rem; - margin-right: 1rem; -} - -.site-header .off-canvas-toggle .svg-icon-menu .svg-icon-menu-path { - fill: #000; -} - -.site-header .off-canvas-toggle .svg-icon-menu:hover .svg-icon-menu-path { - fill: #4183C4; -} - -.site-header .logo { - float: right; - margin-top: 1rem; - text-align: right; - color: #000; -} - -/* page header */ - -.page-header { - background: #ffffff; - margin-top: 1rem; -} - -.page-header .nav-breadcrumbs { - border-bottom: 1px solid #c2d2dc; -} - -.page-header .nav-breadcrumbs ul { - display: block; - overflow: hidden; - margin: 0; - padding: 15px; - list-style: none; - font-size: 0.9em; -} - -.page-header .nav-breadcrumbs li { - float: left; - margin: 0; -} - -.page-header .nav-breadcrumbs li:before { - content: "/"; - margin: 0 5px; - color: #c2d2dc; -} - -.page-header .nav-breadcrumbs li:first-child:before { - content: ""; - margin: 0; -} - -.page-header .nav-breadcrumbs li a { - color: #4078c0; - font-weight: normal; -} - -/* content */ - -.site-content .row { - max-width: 90rem; -} - -.page-content { - background: #ffffff; - min-height: 600px; - padding: 1.25rem 0 2.5rem 0; -} - -/* sidebar */ - -.sidebar { - background: #ffffff; - width: 100%; - padding: 0; -} - -.sidebar .nav-toc { - padding-top: 1rem; -} - -/* navigation */ - -.nav-home { - background: #f7f7f7; - line-height: 2rem; -} - -.nav-home a { - display: block; - color: #4078c0; - font-weight: bold; - font-size: 1rem; - padding-left: 1rem; -} - -.nav-home a.active { - background: #e7e7e7; -} - -.nav-home a:hover { - background: #e7e7e7; - text-decoration: none; -} - -.nav-home a .home-icon { - font-size: 18px; - font-family: "icons" !important; - font-style: normal !important; - font-weight: normal !important; - font-variant: normal !important; - text-transform: none !important; - speak: none; - line-height: 1.2; - vertical-align: middle; - padding-right: 5px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.nav-home .version-number { - padding-left: 1.4rem; - font-size: 0.9rem; -} - -.nav-toc { -} - -.nav-toc ul { - margin: 0; - padding: 0; - line-height: 2rem; -} - -.nav-toc ul > li { - list-style-type: none; - padding-left: 0; -} - -.nav-toc ul > li a { - display: block; - color: #4078c0; - font-weight: bold; - font-size: 0.9rem; - padding-left: 1rem; -} - -.nav-toc ul > li a.active { - background: #e7e7e7; -} - -.nav-toc ul > li a:hover { - background: #e7e7e7; - text-decoration: none; -} - -.nav-toc ul > li > ul li { - margin-top: 0; - border-top: 0; - padding-top: 0; - padding-bottom: 0; -} - -.site-nav ul > li > ul li { - display: none; -} - -.snippet-button { - display: none; -} - -.nav-toc ul > li > ul li a { - font-size: 0.9rem; - font-weight: normal; - text-transform: none; - margin-top: 0; - padding-left: 1.2rem; -} - -/* .nav-toc ul > li a.active ul { - min-height: 200px; -} */ - -.nav-toc ul > li > ul > li > ul li a { - font-size: 0.8rem; - padding-left: 2rem; -} - - -/* site navigation */ - -.site-nav { - padding: 1rem; - /* border: solid 1px #cccccc; */ - background-color: #eee; - border-right: 2px solid #4078c0; -} - -.show-for-medium { - padding-left: 0; -} - -/* off-canvas navigation colours */ - -.off-canvas { -} - -.off-canvas-nav { - padding: 0; -} - -.off-canvas-nav .nav-home { - background: #ffffff; -} - -.off-canvas-nav .nav-toc { - background: #ffffff; -} - -.off-canvas-nav .nav-toc ul > li { -} - -.off-canvas-nav .nav-toc ul > li a { -} - -.off-canvas-nav .nav-toc ul > li a.active { -} - -.off-canvas-nav .nav-toc ul > li a:hover { -} - -.off-canvas-nav .nav-toc ul > li a.active:hover { -} - -.off-canvas-nav .nav-toc ul > li > ul li { - border-top: 0; -} - -/* page navigation */ - -.page-nav { - background: #ffffff; -} - -.page-nav .nav-title { - display: block; - color: #9eb1b7; - font-weight: bold; - font-size: 0.8rem; - padding-left: 1rem; -} - -.page-nav .nav-toc { - background: #ffffff; -} - -.page-nav .nav-toc ul > li { - border-top: 0; -} - -.page-nav .nav-toc ul > li a.active { - background: #4078c0; - color: #ffffff; -} - -.page-nav .nav-toc ul > li a.active:hover { - background: #4078c0; -} - -/* navigation next */ - -.nav-next { - background: #F7F7F7; - border-left: 10px solid #4078c0; - margin-top: 40px; - padding: 1em 20px; -} - -.nav-next p { - display: inline; - color: #0c323b; - font-style: italic; -} - -.nav-next a { - color: #4078c0; - font-weight: normal; -} - -/* table of contents -- ordered */ - -.toc a { - color: #4078c0; - font-weight: normal; -} - -.toc ol li { - color: #778a99; -} - -.toc > ol > li > ol { - list-style-type: lower-alpha; -} - -.toc > ol > li > ol > li > ol { - list-style-type: lower-roman; -} - -.toc.main > ol > li { - margin-top: 0.5em; - font-size: 1.2em; -} - -.toc.main > ol > li { - counter-increment: root; -} - -.toc.main > ol > li > ol { - counter-reset: subsection; - list-style-type: none; - margin-left: 2rem; -} - -.toc.main > ol > li > ol > li { - counter-increment: subsection; -} - -.toc.main > ol > li > ol > li:before { - content: counter(root) "." counter(subsection) ". "; - margin-left: -2rem; - padding-right: 0.25rem; -} - -.toc.main > ol > li > ol > li > ol { - list-style-type: lower-alpha; -} - -.toc.main > ol > li > ol > li > ol > li > ol { - list-style-type: lower-roman; -} - -/* table of contents -- unordered */ - -.toc ul li { - color: #778a99; -} - -.toc.main > ul { - margin-left: 0; - padding-bottom: 2rem; - border-bottom: 1px solid #f3f6f6; -} - -.toc.main > ul > li { - margin-top: 2rem; - border-top: 1px solid #f3f6f6; - padding-top: 2rem; - list-style-type: none; -} - -.toc.main > ul > li > a { - font-weight: bold; -} - -.toc.main > ul > li > ul { - margin-top: 1rem; -} - -.toc.main > ul > li > ul > li { - list-style-type: disc; -} - -.toc.main > ul > li > ul > li > a { - font-weight: normal; - text-transform: none; -} - -.toc.main > ul > li > ul > li > ul > li { - list-style-type: circle; -} - -/* site footer */ - -.site-footer { - margin-top: 3rem; - border-top: solid 1px #cccccc; -} - -.site-footer-content.row { - max-width: 90rem; -} - -.site-footer-nav { - padding: 2rem 0; -} - -.site-footer-nav .with-left-divider { - border-top: 0; - border-left: 1px solid rgba(255, 255, 255, 0.2); -} - -@media screen and (max-width: 40em) { - .site-footer-nav .with-left-divider { - margin-top: 2rem; - border-top: 1px solid rgba(255, 255, 255, 0.2); - padding-top: 2rem; - border-left: 0; - } -} - -@media screen and (min-width: 40em) { - .site-footer-nav .nav-links { - height: 8rem; - } - -} -@media screen and (max-width: 511px) { - #search-block { - display: none !important; - } -} - -.nav-links ul { - margin: 0; - padding: 0; - line-height: 2rem; -} - -.nav-links ul > li { - list-style-type: none; - padding-left: 0; -} - -.nav-links ul > li a { - color: #c5d0d4; - font-weight: bold; - font-size: 0.9rem; -} - -.nav-links ul > li a:hover { - color: #4078C0; - text-decoration: none; -} - -.nav-links ul > li > ul li a { - font-weight: normal; - text-transform: none; -} - -.site-footer-base { - padding: 1rem 0; -} - -.site-footer-base h3, .site-footer-base a { -} - -.site-footer-base .copyright { - margin-top: 20px; -} - -.site-footer-base .copyright .text { - display: inline-block; - line-height: 24px; - padding-right: 10px; - vertical-align: top; -} - -.site-footer-base .svg-icon-logo-text { -} - -.site-footer-base .svg-icon-logo-image { -} - -.site-footer-base .logo:hover .svg-icon-logo-text { -} - -.site-footer-base .logo:hover .svg-icon-logo-image { -} - -.source-github { - padding: 10px; - padding-top: 30px; - margin-top: 20px; - border-top: 1px solid #cccccc; -} - -.source-github a { - font-weight: bold; -} - -.title-wrapper { - display: flex; -} - -.title-logo { - content: url("../imgs/small-otoroshi-logo.png"); - margin-right: 10px; - margin-top: 10px; -} - -p { - text-align: justify; -} - -.centered-img { - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -.hidden { - display: none !important; -} - -.editor { - display: flex; - margin-bottom: 12px; -} - -.editor-quotes { - line-height: 1.45em !important; - font-family: Consolas, "Liberation Mono", Courier, monospace; - font-size: 0.85em !important; - font-weight: normal !important; - background-color: #e6e6e6; -} - -.editor>div:first-child { - min-width: 60%; - max-width: 60%; - padding: 12px !important; -} - -.editor p { - margin: 12px 0 !important; -} - -.editor div:first-child, -.editor div:last-child { - padding: 12px 0; - display: flex; - flex-direction: column; - justify-content: space-around; -} - -.editor div:last-child { - min-width: 40%; - max-width: 40%; - border-radius: 2px; - position: relative; - padding-left: 18px; -} - -.editor-value { - color: #fff; - font-size: .9em; - font-weight: bold; -} - -.editor-title { - font-size: .75em; - text-transform: uppercase; - display: inline-block; - border-radius: 1em; - padding: .25em 1em !important; - background: #45505e; - box-shadow: inset 1px 1px 1px rgb(0 0 0 / 25%); - color: #fff; - margin-bottom: 1.25rem; - margin-left: -0.5rem; - pointer-events: none; - position: absolute; - right: 12px; - top: -24px; -} - -.editor>div:first-child p, -.editor div:last-child p { - display: flex; - flex-direction: column; - margin: 0; -} - -.editor>div:first-child p span { - font-size: .95em; - text-transform: capitalize; - color: #333333; - line-height: 1.45em; - font-family: inherit; -} - -.editor code { - width: fit-content; - border-radius: 4px; - /* white-space: nowrap; */ - background-color: #ddd; -} - -.editor div:first-child code { - margin-right: 4px; -} - -.paste-button { - background: url(../imgs/paste.png) center center no-repeat; - background-size: contain; - height: 100%; - width: 100%; -} - -.paste-button-container { - width: 24px; - height: 24px; - padding: 4px; - background-color: #eee; - border-radius: 6px; - position: absolute; - top: 8px; - right: 8px; -} - -.paste-text { - background-color: #ddd; - border-radius: 6px; - position: absolute; - bottom: 8px; - right: 8px; - padding: 4px; - font-family: inherit; - font-size: .8em; -} - -.nav-toc ul > li > ul li a.page::before { - content: ' - '; - font-weight: bolder; - color: #0d0058; -} - -.element-tag { - position: absolute; - top: 12px; - right: 12px; - border-radius: 4px; - font-size: .85em; - color: #fff; - padding: 4px; -} - -.recommended-tag { - background-color: lightcoral; -} - -.cluster-tag { - background-color: lightseagreen; -} - -#instructions-toggle { - background-color: rgba(64, 120, 192, 0.1); - padding: 12px; - border-radius: 4px; - cursor: pointer; - display: flex !important; - align-items: center; -} - -.instructions-closed { - padding-bottom: 12px !important; -} - -.instructions-title { - flex: 1; - display: block !important; - padding: 0 !important; -} - -#instructions-toggle-button { - display: initial !important; - padding: 6px !important; - background-color: #ddd; - border-radius: 4px; - font-size: .85rem; - font-weight: bold; -} - -.instructions { - border: 1px solid rgba(64, 120, 192, 0.1); - border-radius: 8px; - padding: 12px; - padding-bottom: 0; - margin-bottom: 12px; -} - -.instructions-closed * { - display: none; -} - -#instructions-toggle-confirm { - margin-bottom: 12px; - margin-left: auto; - padding: 12px !important; - background-color: #f9b000; - color: #fff; - border-radius: 4px; - font-size: .85rem; - font-weight: bold; -} \ No newline at end of file diff --git a/docs/manual/css/plugins.css b/docs/manual/css/plugins.css deleted file mode 100644 index fe22417084..0000000000 --- a/docs/manual/css/plugins.css +++ /dev/null @@ -1,257 +0,0 @@ -.plugin { - background-color: #fff !important; - box-shadow: 0 1px 3px rgb(25 25 25 / 30%); - padding: 24px; - border-radius: 4px; - max-width: calc(33% - 36px); - min-width: calc(33% - 36px); - margin: 0 24px 24px 0; - min-height: 360px; - max-height: 360px; - overflow: hidden; - align-items: center; - justify-content: center; - float: left; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; -} - -.ng-plugin { - background-color: #fff !important; - box-shadow: 0 1px 3px rgb(25 25 25 / 30%); - padding: 24px; - border-radius: 4px; - max-width: calc(33% - 36px); - min-width: calc(33% - 36px); - margin: 0 24px 24px 0; - min-height: 260px; - max-height: 260px; - overflow: hidden; - align-items: center; - justify-content: center; - float: left; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; -} - - -@media screen and (max-width: 1440px) { - .plugin { - max-width: calc(50% - 36px); - min-width: calc(50% - 36px); - } - .platform-actions-column { - max-width: calc(100% - 48px) !important; - min-width: calc(100% - 48px) !important; - } -} - -@media screen and (min-width: 1820px) { - .plugin { - max-width: calc(25% - 24px); - min-width: calc(25% - 24px); - } - .platform-actions-column { - max-width: calc(50% - 24px) !important; - min-width: calc(50% - 24px) !important; - } -} - -.script { - min-height: 275px; - max-height: 275px; -} - -.script:hover { - cursor: initial !important; - box-shadow: 0 1px 3px rgb(25 25 25 / 30%) !important; -} - -.plugin:hover { - cursor: pointer; - box-shadow: 0 1px 3px rgba(12,12,12,.5); -} - -.plugin-badge { - background: #95a5a6; - padding: 4px 0 4px; - font-size: 10px; - border-radius: 4px; - color: #fff; - margin-top: auto; - margin-left: auto; - width: 88px; - text-align: center; - text-transform: uppercase; -} - -.plugin-open { - max-width: calc(100% - 72px); - min-width: calc(100% - 72px); - min-height: 100%; - max-height: 100%; - overflow: scroll; -} - -.plugin pre { - /* padding: 1rem !important; */ - border: 1px solid #dddddd !important; - /* margin: 0 0 1rem 0 !important; */ - white-space: pre-wrap; - /* overflow: auto; */ - line-height: 0.9em !important; -} - -.plugin h2 { - font-size: 1.6em; -} - -.filters { - display: flex; - align-items: center; - margin-bottom: 12px; - flex-wrap: wrap; -} - -.filter { - padding: 8px; - background-color: #eee; - margin-right: 4px; - margin-bottom: 4px; - border-radius: 4px; - min-width: 100px; -} - -.filter-selected { - background-color: #fb9000; - color: #fff; -} - - -.plugin-hidden, -.filtered { - display: none; -} - -.platform { - display: flex; - justify-content: center; - max-height: 425px; - min-height: 425px; - position: relative; -} - -.platform img { - max-height: 140px; - margin-top: auto; - margin-bottom: auto; - align-self: center; -} - -.entities a, -.platform a { - padding: 8px; - background-color: #4078c0; - color: #fff; - border-radius: 4px; - box-shadow: 0 1px 3px rgba(12,12,12,.5); - text-decoration: none; - white-space: nowrap; - text-align: center; - flex: 1; - font-size: .9em; -} - -.platform-actions-column a:first-child { - margin-right: 4px; -} - -.platform a:nth-child(n+2):last-child { - margin-left: 4px; - background-color: #fb9000; -} - -.platform p:last-child { - display: flex; - justify-content: center; - align-items: center; - margin-bottom: 0; - width: 100%; - margin-top: auto; -} - -.platform-actions-column { - max-width: calc(66% - 48px); - min-width: calc(66% - 48px); -} - -.platform a:hover { - cursor: pointer !important; -} - -.dark-platform { - background-color: #2e3031 !important; -} - -.dark-platform h2, -.dark-platform p { - color: #fff; -} - -.dark-platform a { - box-shadow: 0 1px 3px rgba(255,255,255,.5); -} - -.break { - margin: 12px 0; - clear: both; -} - -.entities h2, -.entities p { - color: #fff; -} - -.entities { - background-color: #eee !important; - max-width: 75%; - min-width: 75%; - min-height: initial; - max-height: initial; - flex-direction: row; - padding: 0 24px; - align-items: center; - clear: both; - margin-bottom: 12px; -} - -.entities img { - max-height: 36px; - filter: brightness(0); -} - -.entities div:nth-child(2) { - display: flex; - flex-direction: column; - align-items: flex-start; - flex: 1; - margin-left: 12px; -} - -.entities span:first-child { - font-weight: bold; -} - -.entities span { - color: #000; - text-align: left; -} - -.entities a { - flex: 0; - min-width: 60px; -} \ No newline at end of file diff --git a/docs/manual/css/print.css b/docs/manual/css/print.css deleted file mode 100644 index 01a832ebad..0000000000 --- a/docs/manual/css/print.css +++ /dev/null @@ -1,27 +0,0 @@ -h2 { - page-break-before: always; -} -nav.print .toc-page-line { - border-bottom: 1px dashed #bbb; -} -nav.print .toc-page-no { - float: right; -} -nav.print li { - list-style: none; -} - -.print-cover-title { - font-size: 15mm; - padding-top: 150mm; - text-align: center; - width: 100%; -} - -.print-cover-version { - font-size: 10mm; - font-style: italic; - padding-top: 20mm; - text-align: center; - width: 100%; -} \ No newline at end of file diff --git a/docs/manual/css/single.css b/docs/manual/css/single.css deleted file mode 100644 index 0b595f7907..0000000000 --- a/docs/manual/css/single.css +++ /dev/null @@ -1,63 +0,0 @@ -h1 { - counter-reset: h2 h3 1 h4 1 h5 1; -} - -h2 { - counter-increment: h2; - counter-reset: h3 h4 1 h5 1; -} - -h2 .header-title::before { - content: counter(h2); - margin-right: 10px; -} - -h3 { - counter-increment: h3; - counter-reset: h4 h5 1; -} - -h3 .header-title::before { - content: counter(h2) "." counter(h3); - margin-right: 10px; -} - -h4 { - counter-increment: h4; - counter-reset: h5; -} - -h4 .header-title::before { - content: counter(h2) "." counter(h3) "." counter(h4); - margin-right: 1rem; -} - -h5 { - counter-increment: h5; -} - -h5 .header-title::before { - content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5); - margin-right: 1rem; -} - -nav ul { - counter-reset: nav -} - -nav ul > ul { - counter-reset: nav; -} - -nav ul ~ ul { - counter-reset: none; -} - -nav li { - counter-increment: nav; -} - -nav li a::before { - content: counters(nav, "."); - margin-right: 0.5rem -} \ No newline at end of file diff --git a/docs/manual/deploy/aws.html b/docs/manual/deploy/aws.html deleted file mode 100644 index 93896ecf86..0000000000 --- a/docs/manual/deploy/aws.html +++ /dev/null @@ -1,533 +0,0 @@ - - - - -AWS - Elastic Beanstalk · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

AWS - Elastic Beanstalk

-

Now you want to use Otoroshi on AWS. There are multiple options to deploy Otoroshi on AWS, for instance :

- -

In this section we are going to cover how to deploy Otoroshi on AWS Elastic Beanstalk.

-

AWS Elastic Beanstalk Overview

-

Unlike Clever Cloud, to deploy an application on AWS Elastic Beanstalk, you don’t link your app to your VCS repository, push your code and expect it to be built and run.

-

AWS Elastic Beanstalk does only the run part. So you have to handle your own build pipeline, upload a Zip file containing your runnable, then AWS Elastic Beanstalk will take it from there.

-

Eg: for apps running on the JVM (Scala/Java/Kotlin) a Zip with the jar inside would suffice, for apps running in a Docker container, a Zip with the DockerFile would be enough.

-

Prepare your deployment target

-

Actually, there are 2 options to build your target.

-

Either you create a DockerFile from this Docker image, build a zip, and do all the Otoroshi custom configuration using ENVs.

-

Or you download the otoroshi.jar, do all the Otoroshi custom configuration using your own otoroshi.conf, and create a DockerFile that runs the jar using your otoroshi.conf.

-

For the second option your DockerFile would look like this :

-
FROM openjdk:11
-VOLUME /tmp
-EXPOSE 8080
-ADD otoroshi.jar otoroshi.jar
-ADD otoroshi.conf otoroshi.conf
-RUN sh -c 'touch /otoroshi.jar'
-ENV JAVA_OPTS=""
-ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dconfig.file=/otoroshi.conf -jar /otoroshi.jar" ]
-
-

I’d recommend the second option.

-

Now Zip your target (Jar + Conf + DockerFile) and get ready for deployment.

-

Create an Otoroshi instance on AWS Elastic Beanstalk

-

First, go to AWS Elastic Beanstalk Console, don’t forget to sign in and make sure that you are in the good region (eg : eu-west-3 for Paris).

-

Hit Get started

-
-

Specify the Application name of your application, Otoroshi for example.

-
-

Choose the Platform of the application you want to create, in your case use Docker.

-

For Application code choose Upload your code then hit Upload.

-
-

Browse the zip created in the previous section from your machine.

-

As you can see in the image above, you can also choose an S3 location, you can imagine that at the end of your build pipeline you upload your Zip to S3, and then get it from there (I wouldn’t recommend that though).

-

When the upload is done, hit Configure more options.

-
-

Right now an AWS Elastic Beanstalk application has been created, and by default an environment named Otoroshi-env is being created as well.

-

AWS Elastic Beanstalk can manage multiple environments of the same application, for instance environments can be (prod, preprod, expriments…).

-

Otoroshi is a bit particular, it doesn’t make much sense to have multiple environments, since Otoroshi will handle all the requests from/to backend services regardless of the environment.

-

As you see in the image above, we are now configuring the Otoroshi-env, the one and only environment of Otoroshi.

-

For Configuration presets, choose custom configuration, now you have a load balancer for your environment with the capacity of at least one instance and at most four. I’d recommend at least 2 instances, to change that, on the Capacity card hit Modify.

-
-

Change the Instances to min 2, max 4 then hit Save. For the Scaling triggers, I’d keep the default values, but know that you can edit the capacity config any time you want, it only costs a redeploy, which will be done automatically by the way.

-

Instances size is by default t2.micro, which is a bit small for running Otoroshi, I’d recommend a t2.medium.
On the Instances card hit Modify.

-
-

For Instance type choose t2.medium, then hit Save, no need to change the volume size, unless you have a lot of http call faults, which means a lot more logs, in that case the default volume size may not be enough.

-

The default environment created for Otoroshi, for instance Otoroshi-env, is a web server environment which fits in your case, but the thing is that on AWS Elastic Beanstalk by default a web server environment for a docker-based application, runs behind an Nginx proxy. We have to remove that proxy. So on the Software card hit Modify.

-
-

For Proxy server choose None then hit Save.

-

Also note that you can set Envs for Otoroshi in same page (see image below).

-
-

To finalise the creation process, hit Create app on the bottom right.

-

The Otoroshi app is now created, and it’s running which is cool, but we still don’t have neither a datastore nor https.

-

Create an Otoroshi datastore on AWS ElastiCache

-

By default Otoroshi uses non persistent memory to store it’s data, Otoroshi supports many kinds of datastores. In this section we will be covering Redis datastore.

-

Before starting, using a datastore hosted by AWS is not at all mandatory, feel free to use your own if you like, but if you want to learn more about ElastiCache, this section may interest you, otherwise you can skip it.

-

Go to AWS ElastiCache and hit Get Started Now.

-
-

For Cluster engine keep Redis.

-

Choose a Name for your datastore, for instance otoroshi-datastore.

-

You can keep all the other default values and hit Create on the bottom right of the page.

-

Once your Redis Cluster is created, it would look like the image below.

-
-

For applications in the same security group as your cluster, redis cluster is accessible via the Primary Endpoint. Don’t worry the default security group is fine, you don’t need any configuration to access the cluster from Otoroshi.

-

To make Otoroshi use the created cluster, you can either use Envs APP_STORAGE=redis, REDIS_HOST and REDIS_PORT, or set otoroshi.storage=redis, otoroshi.redis.host and otoroshi.redis.port in your otoroshi.conf.

-

Create SSL certificate and configure your domain

-

Otoroshi has now a datastore, but not yet ready for use.

-

In order to get it ready you need to :

-
    -
  • Configure Otoroshi with your domain
  • -
  • Create a wildcard SSL certificate for your domain
  • -
  • Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate
  • -
  • Configure your DNS to redirect all traffic on your domain to Otoroshi
  • -
-

Configure Otoroshi with your domain

-

You can use ENVs or you can use a custom otoroshi.conf in your Docker container.

-

For the second option your otoroshi.conf would look like this :

-
   include "application.conf"
-   http.port = 8080
-   app {
-     env = "prod"
-     domain = "mysubdomain.oto.tools"
-     rootScheme = "https"
-     snowflake {
-       seed = 0
-     }
-     events {
-       maxSize = 1000
-     }
-     backoffice {
-       subdomain = "otoroshi"
-       session {
-         exp = 86400000
-       }
-     }
-     
-     storage = "redis"
-     redis {
-        host="myredishost"
-        port=myredisport
-     }
-   
-     privateapps {
-       subdomain = "privateapps"
-     }
-   
-     adminapi {
-       targetSubdomain = "otoroshi-admin-internal-api"
-       exposedSubdomain = "otoroshi-api"
-       defaultValues {
-         backOfficeGroupId = "admin-api-group"
-         backOfficeApiKeyClientId = "admin-client-id"
-         backOfficeApiKeyClientSecret = "admin-client-secret"
-         backOfficeServiceId = "admin-api-service"
-       }
-       proxy {
-         https = true
-         local = false
-       }
-     }
-     claim {
-       sharedKey = "myclaimsharedkey"
-     }
-   }
-   
-   play.http {
-     session {
-       secure = false
-       httpOnly = true
-       maxAge = 2147483646
-       domain = ".mysubdomain.oto.tools"
-       cookieName = "oto-sess"
-     }
-   }
-
-

Create a wildcard SSL certificate for your domain

-

Go to AWS Certificate Manager.

-

Below Provision certificates hit Get started.

-
-

Keep the default selected value Request a public certificate and hit Request a certificate.

-
-

Put your Domain name, use *. for wildcard, for instance *.mysubdomain.oto.tools, then hit Next.

-
-

You can choose between Email validation and DNS validation, I’d recommend DNS validation, then hit Review.

-
-

Verify that you did put the right Domain name then hit Confirm and request.

-
-

As you see in the image above, to let Amazon do the validation you have to add the CNAME record to your DNS configuration. Normally this operation takes around one day.

-

Configure Otoroshi AWS Elastic Beanstalk instance with the SSL certificate

-

Once the certificate is validated, you need to modify the configuration of Otoroshi-env to add the SSL certificate for HTTPS. For that you need to go to AWS Elastic Beanstalk applications, hit Otoroshi-env, then on the left side hit Configuration, then on the Load balancer card hit Modify.

-
-

In the Application Load Balancer section hit Add listener.

-
-

Fill the popup as the image above, then hit Add.

-

You should now be seeing something like this :

-
-

Make sure that your listener is enabled, and on the bottom right of the page hit Apply.

-

Now you have https, so let’s use Otoroshi.

-

Configure your DNS to redirect all traffic on your domain to Otoroshi

-

It’s actually pretty simple, you just need to add a CNAME record to your DNS configuration, that redirects *.mysubdomain.oto.tools to the DNS name of Otoroshi’s load balancer.

-

To find the DNS name of Otoroshi’s load balancer go to AWS Ec2

-

You would find something like this :

-
-

There is your DNS name, so add your CNAME record.

-

Once all these steps are done, the AWS Elastic Beanstalk Otoroshi instance, would now be handling all the requests on your domain. ;)

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/deploy/clever-cloud.html b/docs/manual/deploy/clever-cloud.html deleted file mode 100644 index 6a62d25f9a..0000000000 --- a/docs/manual/deploy/clever-cloud.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - -Clever-Cloud · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Clever-Cloud

-

Now you want to use Otoroshi on Clever Cloud. Otoroshi has been designed and created to run on Clever Cloud and a lot of choices were made because of how Clever Cloud works.

-

Create an Otoroshi instance on CleverCloud

-

If you want to customize the configuration use env. variables, you can use the example provided below

-

Create a new CleverCloud app based on a clevercloud git repo (not empty) or a github project of your own (not empty).

-
-

Then choose what kind of app your want to create, for Otoroshi, choose Java + Jar

-
-

Next, set up choose instance size and auto-scalling. Otoroshi can run on small instances, especially if you just want to test it.

-
-

Finally, choose a name for your app

-
-

Now you just need to customize environnment variables

-

at this point, you can also add other env. variables to configure Otoroshi like in the example provided below

-
-

You can also use expert mode :

-
-

Now, your app is ready, don’t forget to add a custom domains name on the CleverCloud app matching the Otoroshi app domain.

-

Example of CleverCloud env. variables

-

You can add more env variables to customize your Otoroshi instance like the following. Use the expert mode to copy/paste all the values in one shot. If you want an real datastore, create a redis addon on clevercloud, link it to your otoroshi app and change the APP_STORAGE variable to redis

-
-
-``` -ADMIN_API_CLIENT_ID=xxxx -ADMIN_API_CLIENT_SECRET=xxxxx -ADMIN_API_GROUP=xxxxxx -ADMIN_API_SERVICE_ID=xxxxxxx -CLAIM_SHAREDKEY=xxxxxxx -OTOROSHI_INITIAL_ADMIN_LOGIN=youremailaddress -OTOROSHI_INITIAL_ADMIN_PASSWORD=yourpassword -PLAY_CRYPTO_SECRET=xxxxxx -SESSION_NAME=oto-session -APP_DOMAIN=yourdomain.tech -APP_ENV=prod -APP_STORAGE=inmemory -APP_ROOT_SCHEME=https -CC_PRE_BUILD_HOOK=curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/${latest_otoroshi_version}/otoroshi.jar' -CC_JAR_PATH=./otoroshi.jar -CC_JAVA_VERSION=11 -PORT=8080 -SESSION_DOMAIN=.yourdomain.tech -SESSION_MAX_AGE=604800000 -SESSION_SECURE_ONLY=true -USER_AGENT=otoroshi -MAX_EVENTS_SIZE=1 -WEBHOOK_SIZE=100 -APP_BACKOFFICE_SESSION_EXP=86400000 -APP_PRIVATEAPPS_SESSION_EXP=86400000 -ENABLE_METRICS=true -OTOROSHI_ANALYTICS_PRESSURE_ENABLED=true -USE_CACHE=true -``` -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/deploy/clustering.html b/docs/manual/deploy/clustering.html deleted file mode 100644 index 787fe6eccb..0000000000 --- a/docs/manual/deploy/clustering.html +++ /dev/null @@ -1,451 +0,0 @@ - - - - -Otoroshi clustering · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Otoroshi clustering

-

Otoroshi can work as a cluster by default as you can spin many Otoroshi servers using the same datastore or datastore cluster. In that case any instance is capable of serving services, Otoroshi admin UI, Otoroshi admin API, etc.

-

But sometimes, this is not enough. So Otoroshi provides an additional clustering model named Leader / Workers where there is a leader cluster (control plane), composed of Otoroshi instances backed by a datastore like Redis, PostgreSQL or Cassandra, that is in charge of all writes to the datastore through Otoroshi admin UI and API, and a worker cluster (data plane) composed of horizontally scalable Otoroshi instances, backed by a super fast in memory datastore, with the sole purpose of routing traffic to your services based on data synced from the leader cluster. With this distributed Otoroshi version, you can reach your goals of high availability, scalability and security.

-

Otoroshi clustering only uses http internally (right now) to make communications between leaders and workers instances so it is fully compatible with PaaS providers like Clever-Cloud that only provide one external port for http traffic.

- -

Fig. 1: Simplified view

- -

Fig. 2: Deployment view

-

Cluster configuration

-
otoroshi {
-  cluster {
-    mode = "leader" # can be "off", "leader", "worker"
-    compression = 4 # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9
-    leader {
-      name = ${?CLUSTER_LEADER_NAME}   # name of the instance, if none, it will be generated
-      urls = ["http://127.0.0.1:8080"] # urls to contact the leader cluster
-      host = "otoroshi-api.oto.tools"    # host of the otoroshi api in the leader cluster
-      clientId = "apikey-id"           # otoroshi api client id
-      clientSecret = "secret"          # otoroshi api client secret
-      cacheStateFor = 4000             # state is cached during (ms)
-    }
-    worker {
-      name = ${?CLUSTER_WORKER_NAME}   # name of the instance, if none, it will be generated
-      retries = 3                      # number of retries when calling leader cluster
-      timeout = 2000                   # timeout when calling leader cluster
-      state {
-        retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on state sync
-        pollEvery = 10000                            # interval of time (ms) between 2 state sync
-        timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on state sync
-      }
-      quotas {
-        retries = ${otoroshi.cluster.worker.retries} # number of retries when calling leader cluster on quotas sync
-        pushEvery = 2000                             # interval of time (ms) between 2 quotas sync
-        timeout = ${otoroshi.cluster.worker.timeout} # timeout when calling leader cluster on quotas sync
-      }
-    }
-  }
-}
-
-

you can also use many env. variables to configure Otoroshi cluster

-
otoroshi {
-  cluster {
-    mode = ${?CLUSTER_MODE}
-    compression = ${?CLUSTER_COMPRESSION}
-    leader {
-      name = ${?CLUSTER_LEADER_NAME}
-      host = ${?CLUSTER_LEADER_HOST}
-      url = ${?CLUSTER_LEADER_URL}
-      clientId = ${?CLUSTER_LEADER_CLIENT_ID}
-      clientSecret = ${?CLUSTER_LEADER_CLIENT_SECRET}
-      groupingBy = ${?CLUSTER_LEADER_GROUP_BY}
-      cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR}
-      stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH}
-    }
-    worker {
-      name = ${?CLUSTER_WORKER_NAME}
-      retries = ${?CLUSTER_WORKER_RETRIES}
-      timeout = ${?CLUSTER_WORKER_TIMEOUT}
-      state {
-        retries = ${?CLUSTER_WORKER_STATE_RETRIES}
-        pollEvery = ${?CLUSTER_WORKER_POLL_EVERY}
-        timeout = ${?CLUSTER_WORKER_POLL_TIMEOUT}
-      }
-      quotas {
-        retries = ${?CLUSTER_WORKER_QUOTAS_RETRIES}
-        pushEvery = ${?CLUSTER_WORKER_PUSH_EVERY}
-        timeout = ${?CLUSTER_WORKER_PUSH_TIMEOUT}
-      }
-    }
-  }
-}
-
Warning
-

You should use HTTPS exposition for the Otoroshi API that will be used for data sync as sensitive informations are exchanged between control plane and data plane.

Warning
-

You must have the same cluster configuration on every Otoroshi instance (worker/leader) with only names and mode changed for each instance. Some things in leader/worker are computed using configuration of their counterpart worker/leader.

-

Cluster UI

-

Once an Otoroshi instance is launcher as cluster Leader, a new row of live metrics tile will be available on the home page of Otoroshi admin UI.

-
-

you can also access a more detailed view of the cluster at Settings (cog icon) / Cluster View

-
-

Run examples

-

for leader

-
java -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar
-
-

for worker

-
java -Dhttp.port=8092 -Dhttps.port=9092 -Dotoroshi.cluster.mode=worker \
-  -Dotoroshi.cluster.leader.urls.0=http://127.0.0.1:8091 -jar otoroshi.jar
-
-

Setup a cluster by example

-

if you want to see how to setup an otoroshi cluster, just check the clustering tutorial

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/deploy/index.html b/docs/manual/deploy/index.html deleted file mode 100644 index d28a71300b..0000000000 --- a/docs/manual/deploy/index.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - -Deploy to production · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Deploy to production

-

Now it’s time to deploy Otoroshi in production, in this chapter we will see what kind of things you can do.

-

Otoroshi can run wherever you want, even on a raspberry pi (Cluster^^) ;)

-

Clever Cloud

-

Otoroshi provides an integration to create easily services based on application deployed on your Clever Cloud account.

- -

Documentation

-

Kubernetes

-

Starting at version 1.5.0, Otoroshi provides a native Kubernetes support.

- -

Documentation

-

AWS Elastic Beanstalk

-

Run Otoroshi on AWS Elastic Beanstalk

- -

Tutorial

-

Amazon ECS

-

Deploy the Otoroshi Docker image using Amazon Elastic Container Service

- -

Tutorial Docker image

-

GCE

-

Deploy the Docker image using Google Compute Engine container integration

- -

Documentation Docker image

-

Azure

-

Deploy the Docker image using Azure Container Service

- -

Documentation Docker image

-

Heroku

-

Deploy the Docker image using Docker integration

- -

Documentation Docker image

-

CloudFoundry

-

Deploy the Docker image using -Docker integration

- -

Documentation Docker image

-

Your own infrastructure

-

As Otoroshi is a Play Framework application, you can read the doc about putting a Play app in production.

-

Download the latest Otoroshi distribution, unzip it, customize it and run it.

-

Play Framework Production Configuration Otoroshi distribution

-

Scaling and clustering in production

-

Clustering

-

Deploy Otoroshi as a cluster of leaders and workers.

- -

Documentation

-

Scaling Otoroshi

-

Otoroshi is designed to be reasonably easy to scale and be highly available.

- -

Documentation

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/deploy/kubernetes.html b/docs/manual/deploy/kubernetes.html deleted file mode 100644 index 5c1d011465..0000000000 --- a/docs/manual/deploy/kubernetes.html +++ /dev/null @@ -1,4868 +0,0 @@ - - - - -Kubernetes · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Kubernetes

-

Starting at version 1.5.0, Otoroshi provides a native Kubernetes support. Multiple otoroshi jobs (that are actually kubernetes controllers) are provided in order to

-
    -
  • sync kubernetes secrets of type kubernetes.io/tls to otoroshi certificates
  • -
  • act as a standard ingress controller (supporting Ingress objects)
  • -
  • provide Custom Resource Definitions (CRDs) to manage Otoroshi entities from Kubernetes and act as an ingress controller with its own resources
  • -
-

Installing otoroshi on your kubernetes cluster

Warning
-

You need to have cluster admin privileges to install otoroshi and its service account, role mapping and CRDs on a kubernetes cluster. We also advise you to create a dedicated namespace (you can name it otoroshi for example) to install otoroshi

-

If you want to deploy otoroshi into your kubernetes cluster, you can download the deployment descriptors from https://github.com/MAIF/otoroshi/tree/master/kubernetes and use kustomize to create your own overlay.

-

You can also create a kustomization.yaml file with a remote base

-
bases:
-- github.com/MAIF/otoroshi/kubernetes/kustomize/overlays/simple/?ref=v1.5.11
-
-

Then deploy it with kubectl apply -k ./overlays/myoverlay.

-

You can also use Helm to deploy a simple otoroshi cluster on your kubernetes cluster

-
helm repo add otoroshi https://maif.github.io/otoroshi/helm
-helm install my-otoroshi otoroshi/otoroshi
-
-

Below, you will find example of deployment. Do not hesitate to adapt them to your needs. Those descriptors have value placeholders that you will need to replace with actual values like

-
 env:
-  - name: APP_STORAGE_ROOT
-    value: otoroshi
-  - name: APP_DOMAIN
-    value: ${domain}
-
-

you will have to edit it to make it look like

-
 env:
-  - name: APP_STORAGE_ROOT
-    value: otoroshi
-  - name: APP_DOMAIN
-    value: 'apis.my.domain'
-
-

if you don’t want to use placeholders and environment variables, you can create a secret containing the configuration file of otoroshi

-
apiVersion: v1
-kind: Secret
-metadata:
-  name: otoroshi-config
-type: Opaque
-stringData:
-  oto.conf: >
-    include "application.conf"
-    app {
-      storage = "redis"
-      domain = "apis.my.domain"
-    }
-
-

and mount it in the otoroshi container

-
apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-deployment
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      containers:
-      - image: maif/otoroshi:1.5.11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        args: ['-Dconfig.file=/usr/app/otoroshi/conf/oto.conf']
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        volumeMounts:
-        - name: otoroshi-config
-          mountPath: "/usr/app/otoroshi/conf"
-          readOnly: true
-      volumes:
-      - name: otoroshi-config
-        secret:
-          secretName: otoroshi-config
-        ...
-
-

You can also create several secrets for each placeholder, mount them to the otoroshi container then use their file path as value

-
 env:
-  - name: APP_STORAGE_ROOT
-    value: otoroshi
-  - name: APP_DOMAIN
-    value: 'file:///the/path/of/the/secret/file'
-
-

you can use the same trick in the config. file itself

-

Note on bare metal kubernetes cluster installation

Note
-

Bare metal kubernetes clusters don’t come with support for external loadbalancers (service of type LoadBalancer). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like MetalLB that provide software LoadBalancer services to bare metal clusters or you can use and customize examples below.

Warning
-

We don’t recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.

-

Common manifests

-

the following manifests are always needed. They create otoroshi CRDs, tokens, role, etc. Redis deployment is not mandatory, it’s just an example. You can use your own existing setup.

-
-
rbac.yaml -
-
-
---
-kind: ServiceAccount
-apiVersion: v1
-metadata:
-  name: otoroshi-admin-user
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  name: otoroshi-admin-user
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: otoroshi-admin-user
-subjects:
-- kind: ServiceAccount
-  name: otoroshi-admin-user
-  namespace: $namespace
----
-kind: ClusterRole
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: otoroshi-admin-user
-rules:
-  - apiGroups:
-      - ""
-    resources:
-      - services
-      - endpoints
-      - secrets
-      - configmaps
-      - deployments
-      - namespaces
-      - pods
-    verbs:
-      - get
-      - list
-      - watch
-  - apiGroups:
-      - ""
-    resources:
-      - secrets
-      - configmaps
-    verbs:
-      - update
-      - create
-      - delete
-  - apiGroups:
-      - extensions
-    resources:
-      - ingresses
-      - ingressclasses
-    verbs:
-      - get
-      - list
-      - watch
-  - apiGroups:
-      - extensions
-    resources:
-      - ingresses/status
-    verbs:
-      - update
-  - apiGroups:
-      - admissionregistration.k8s.io
-    resources:
-      - validatingwebhookconfigurations
-      - mutatingwebhookconfigurations
-    verbs:
-      - get
-      - update
-      - patch
-  - apiGroups:
-      - proxy.otoroshi.io
-    resources:
-      - service-groups
-      - service-descriptors
-      - apikeys
-      - certificates
-      - global-configs
-      - jwt-verifiers
-      - auth-modules
-      - scripts
-      - tcp-services
-      - data-exporters
-      - admins
-      - organizations
-      - teams
-      - routes
-      - services
-      - backends
-      - target
-    verbs:
-      - get
-      - list
-      - watch
-
crds.yaml -
-
-
---
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: service-groups.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  #validation:
-  #  openAPIV3Schema:
-  #    type: object
-  #    properties:
-  #      spec:
-  #        type: object
-  #        properties:
-  #          name:
-  #            type: string
-  #          description:
-  #            type: string
-  #          metadata:
-  #            type: object
-  names:
-    kind: ServiceGroup
-    plural: service-groups
-    singular: service-group
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: organizations.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: Organization
-    plural: organizations
-    singular: organization
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: teams.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: Team
-    plural: teams
-    singular: team
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: service-descriptors.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  #validation:
-  #  openAPIV3Schema:
-  #    type: object
-  #    properties:
-  #      spec:
-  #        type: object
-  #        properties:
-  #          group:
-  #            type: string
-  #          name:
-  #            type: string
-  #          env:
-  #            type: string
-  #          domain:
-  #            type: string
-  #          subdomain:
-  #            type: string
-  #          root:
-  #            type: string
-  #          matchingRoot:
-  #            type: string
-  #          stripPath:
-  #            type: boolean
-  #          enabled:
-  #            type: boolean
-  #          userFacing:
-  #            type: boolean
-  #          privateApp:
-  #            type: boolean
-  #          forceHttps:
-  #            type: boolean
-  #          maintenanceMode:
-  #            type: boolean
-  #          buildMode:
-  #            type: boolean
-  #          strictlyPrivate:
-  #            type: boolean
-  #          sendOtoroshiHeadersBack:
-  #            type: boolean
-  #          readOnly:
-  #            type: boolean
-  #          xForwardedHeaders:
-  #            type: boolean
-  #          overrideHost:
-  #            type: boolean
-  #          allowHttp10:
-  #            type: boolean
-  #          logAnalyticsOnServer:
-  #            type: boolean
-  #          useAkkaHttpClient:
-  #            type: boolean
-  #          useNewWSClient:
-  #            type: boolean
-  #          tcpUdpTunneling:
-  #            type: boolean
-  #          detectApiKeySooner:
-  #            type: boolean
-  #          letsEncrypt:
-  #            type: boolean
-  #          enforceSecureCommunication:
-  #            type: boolean
-  #          sendInfoToken:
-  #            type: boolean
-  #          sendStateChallenge:
-  #            type: boolean
-  #          securityExcludedPatterns:
-  #            type: array
-  #          publicPatterns:
-  #            type: array
-  #          privatePatterns:
-  #            type: array
-  #          additionalHeaders:
-  #            type: object
-  #          additionalHeadersOut:
-  #            type: object
-  #          missingOnlyHeadersIn:
-  #            type: object
-  #          missingOnlyHeadersOut:
-  #            type: object
-  #          removeHeadersIn:
-  #            type: array
-  #          removeHeadersOut:
-  #            type: array
-  #          headersVerification:
-  #            type: object
-  #          matchingHeaders:
-  #            type: object
-  #          metadata:
-  #            type: object
-  #          hosts:
-  #            type: array
-  #          paths:
-  #            type: array
-  #          issueCert:
-  #            type: boolean
-  #          issueCertCA:
-  #            type: string
-  names:
-    kind: ServiceDescriptor
-    plural: service-descriptors
-    singular: service-descriptor
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: apikeys.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  #validation:
-  #  openAPIV3Schema:
-  #    type: object
-  #    properties:
-  #      spec:
-  #        type: object
-  #        properties:
-  #          daikokuToken:
-  #            type: string
-  #          secretName: 
-  #            type: string
-  #          exportSecret:
-  #            type: boolean
-  #          clientId:
-  #            type: string
-  #          clientSecret:
-  #            type: string
-  #          clientName:
-  #            type: string
-  #          authorizedEntities:
-  #            type: array
-  #          group:
-  #            type: string
-  #          enabled:
-  #            type: boolean
-  #          readOnly:
-  #            type: boolean
-  #          allowClientIdOnly:
-  #            type: boolean
-  #          throttlingQuota:
-  #            type: integer
-  #            format: int64
-  #          dailyQuota:
-  #            type: integer
-  #            format: int64
-  #          monthlyQuota:
-  #            type: integer
-  #            format: int64
-  #          constrainedServicesOnly:
-  #            type: boolean
-  #          validUntil:
-  #            type: integer
-  #            format: int64
-  #          tags:
-  #            type: array
-  #          metadata:
-  #            type: object
-  names:
-    kind: ApiKey
-    plural: apikeys
-    singular: apikey
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: certificates.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  #validation:
-  #  openAPIV3Schema:
-  #    type: object
-  #    properties:
-  #      spec:
-  #        type: object
-  #        required: ["csr"]
-  #        properties:
-  #          name:
-  #            type: string
-  #          description:
-  #            type: string
-  #          secretName: 
-  #            type: string
-  #          exportSecret:
-  #            type: boolean
-  #          selfSigned:
-  #            type: boolean
-  #          ca:
-  #            type: boolean
-  #          autoRenew:
-  #            type: boolean
-  #          letsEncrypt:
-  #            type: boolean
-  #          client:
-  #            type: boolean
-  #          entityMetadata:
-  #            type: object
-  #          csr:
-  #            type: object
-  names:
-    kind: Certificate
-    plural: certificates
-    singular: certificate
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: global-configs.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: GlobalConfig
-    plural: global-configs
-    singular: global-config
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: jwt-verifiers.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: JwtVerifier
-    plural: jwt-verifiers
-    singular: jwt-verifier
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: auth-modules.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: AuthModule
-    plural: auth-modules
-    singular: auth-module
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: scripts.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  #validation:
-  #  openAPIV3Schema:
-  #    type: object
-  #    properties:
-  #      spec:
-  #        type: object
-  #        required: ["code", "type"]
-  #        properties:
-  #          name:
-  #            type: string
-  #          desc:
-  #            type: string
-  #          code:
-  #            type: string
-  #          type:
-  #            type: string
-  #          metadata:
-  #            type: object
-  names:
-    kind: Script
-    plural: scripts
-    singular: script
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tcp-services.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: TcpService
-    plural: tcp-services
-    singular: tcp-service
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: data-exporters.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: DataExporter
-    plural: data-exporters
-    singular: data-exporter
-  scope: Namespaced
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: admins.proxy.otoroshi.io
-spec:
-  group: proxy.otoroshi.io
-  version: v1alpha1
-  preserveUnknownFields: true
-  names:
-    kind: Admin
-    plural: admins
-    singular: admin
-  scope: Namespaced
-
redis.yaml -
-
-
apiVersion: v1
-kind: Service
-metadata:
-  name: redis-leader-service
-spec:
-  ports:
-    - port: 6379
-      name: redis
-  selector:
-    run: redis-leader-deployment
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: redis-follower-service
-spec:
-  ports:
-    - port: 6379
-      name: redis
-  selector:
-    run: redis-follower-deployment
----
-apiVersion: apps/v1
-kind: StatefulSet
-metadata:
-  name: redis-leader-deployment
-spec:
-  selector:
-    matchLabels:
-      run: redis-leader-deployment
-  serviceName: redis-leader-service
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        run: redis-leader-deployment
-    spec:
-      containers:
-        - name: redis-leader-container
-          image: redis
-          imagePullPolicy: Always
-          command: ["redis-server", "--appendonly", "yes"]
-          ports:
-            - containerPort: 6379
-              name: redis
-          volumeMounts:
-          - name: redis-leader-storage
-            mountPath: /data
-            readOnly: false
-          readinessProbe:
-            exec:
-              command:
-              - sh
-              - -c
-              - "redis-cli -h $(hostname) ping"
-            initialDelaySeconds: 15
-            timeoutSeconds: 5
-          livenessProbe:
-            exec:
-              command:
-              - sh
-              - -c
-              - "redis-cli -h $(hostname) ping"
-            initialDelaySeconds: 20
-            periodSeconds: 3
-  volumeClaimTemplates:
-  - metadata:
-      name: redis-leader-storage
-      labels:
-        name: redis-leader-storage
-      annotations:
-        volume.alpha.kubernetes.io/storage-class: anything
-    spec:
-      accessModes: [ "ReadWriteOnce" ]
-      resources:
-        requests:
-          storage: 100Mi
----
-apiVersion: apps/v1
-kind: StatefulSet
-metadata:
-  name: redis-follower-deployment
-spec:
-  selector:
-    matchLabels:
-      run: redis-follower-deployment
-  serviceName: redis-follower-service
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        run: redis-follower-deployment
-    spec:
-      containers:
-        - name: redis-follower-container
-          image: redis
-          imagePullPolicy: Always
-          command: ["redis-server", "--appendonly", "yes", "--slaveof", "redis-leader-service", "6379"]
-          ports:
-            - containerPort: 6379
-              name: redis
-          volumeMounts:
-          - name: redis-follower-storage
-            mountPath: /data
-            readOnly: false
-          readinessProbe:
-            exec:
-              command:
-              - sh
-              - -c
-              - "redis-cli -h $(hostname) ping"
-            initialDelaySeconds: 15
-            timeoutSeconds: 5
-          livenessProbe:
-            exec:
-              command:
-              - sh
-              - -c
-              - "redis-cli -h $(hostname) ping"
-            initialDelaySeconds: 20
-            periodSeconds: 3
-  volumeClaimTemplates:
-  - metadata:
-      name: redis-follower-storage
-      labels:
-        name: redis-follower-storage
-      annotations:
-        volume.alpha.kubernetes.io/storage-class: anything
-    spec:
-      accessModes: [ "ReadWriteOnce" ]
-      resources:
-        requests:
-          storage: 100Mi
-
-

Deploy a simple otoroshi instanciation on a cloud provider managed kubernetes cluster

-

Here we have 2 replicas connected to the same redis instance. Nothing fancy. We use a service of type LoadBalancer to expose otoroshi to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the LoadBalancer external CNAME (see the example below)

-
-
deployment.yaml -
-
-
apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-deployment
-  replicas: 2
-  strategy:
-    type: RollingUpdate
-    rollingUpdate:
-      maxUnavailable: 1
-      maxSurge: 1
-  template:
-    metadata:
-      labels:
-        run: otoroshi-deployment
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-api-service.${namespace}.svc.cluster.local
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }  
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        resources:
-          # requests:
-          #   cpu: "100m"
-          #   memory: "50Mi"
-          # limits:
-          #   cpu: "4G"
-          #   memory: "4Gi"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-service
-spec:
-  selector:
-    run: otoroshi-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-external-service
-spec:
-  type: LoadBalancer
-  selector:
-    run: otoroshi-deployment
-  ports:
-  - port: 80
-    name: "http"
-    targetPort: "http"
-  - port: 443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
dns.example -
-
-
otoroshi.your.otoroshi.domain      IN CNAME generated.cname.of.your.cluster.loadbalancer
-otoroshi-api.your.otoroshi.domain  IN CNAME generated.cname.of.your.cluster.loadbalancer
-privateapps.your.otoroshi.domain   IN CNAME generated.cname.of.your.cluster.loadbalancer
-api1.another.domain                IN CNAME generated.cname.of.your.cluster.loadbalancer
-api2.another.domain                IN CNAME generated.cname.of.your.cluster.loadbalancer
-*.api.the.api.domain               IN CNAME generated.cname.of.your.cluster.loadbalancer
-
-

Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster

-

Here we have 2 replicas connected to the same redis instance. Nothing fancy. The otoroshi instance are exposed as nodePort so you’ll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below).

-
-
deployment.yaml -
-
-
apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-deployment
-  replicas: 2
-  strategy:
-    type: RollingUpdate
-    rollingUpdate:
-      maxUnavailable: 1
-      maxSurge: 1
-  template:
-    metadata:
-      labels:
-        run: otoroshi-deployment
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-api-service.${namespace}.svc.cluster.local
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }  
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        resources:
-          # requests:
-          #   cpu: "100m"
-          #   memory: "50Mi"
-          # limits:
-          #   cpu: "4G"
-          #   memory: "4Gi"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-service
-spec:
-  selector:
-    run: otoroshi-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-external-service
-spec:
-  selector:
-    run: otoroshi-deployment
-  ports:
-  - port: 80
-    name: "http"
-    targetPort: "http"
-    nodePort: 31080
-  - port: 443
-    name: "https"
-    targetPort: "https"
-    nodePort: 31443
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
haproxy.example -
-
-
frontend front_nodes_http
-    bind *:80
-    mode tcp
-    default_backend back_http_nodes
-    timeout client          1m
-
-frontend front_nodes_https
-    bind *:443
-    mode tcp
-    default_backend back_https_nodes
-    timeout client          1m
-
-backend back_http_nodes
-    mode tcp
-    balance roundrobin
-    server kubernetes-node1 10.2.2.40:31080
-    server kubernetes-node2 10.2.2.41:31080
-    server kubernetes-node3 10.2.2.42:31080
-    timeout connect        10s
-    timeout server          1m
-
-backend back_https_nodes
-    mode tcp
-    balance roundrobin
-    server kubernetes-node1 10.2.2.40:31443
-    server kubernetes-node2 10.2.2.41:31443
-    server kubernetes-node3 10.2.2.42:31443
-    timeout connect        10s
-    timeout server          1m
-
nginx.example -
-
-
stream {
-
-  upstream back_http_nodes {
-    zone back_http_nodes 64k;
-    server 10.2.2.40:31080 max_fails=1;
-    server 10.2.2.41:31080 max_fails=1;
-    server 10.2.2.42:31080 max_fails=1;
-  }
-
-  upstream back_https_nodes {
-    zone back_https_nodes 64k;
-    server 10.2.2.40:31443 max_fails=1;
-    server 10.2.2.41:31443 max_fails=1;
-    server 10.2.2.42:31443 max_fails=1;
-  }
-
-  server {
-    listen     80;
-    proxy_pass back_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     443;
-    proxy_pass back_https_nodes;
-    health_check;
-  }
-  
-}
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
-

Deploy a simple otoroshi instanciation on a bare metal kubernetes cluster using a DaemonSet

-

Here we have one otoroshi instance on each kubernetes node (with the otoroshi-kind: instance label) with redis persistance. The otoroshi instances are exposed as hostPort so you’ll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below).

-
-
deployment.yaml -
-
-
apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  name: otoroshi-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-deployment
-    spec:
-      affinity:
-        nodeAffinity:
-          requiredDuringSchedulingIgnoredDuringExecution:
-            nodeSelectorTerms:
-            - matchExpressions:
-              - key: otoroshi-kind
-                operator: In
-                values:
-                - instance
-      tolerations:
-      - key: node-role.kubernetes.io/master
-        effect: NoSchedule
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      restartPolicy: Always
-      hostNetwork: false
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        ports:
-          - containerPort: 8080
-            hostPort: 41080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            hostPort: 41443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-api-service.${namespace}.svc.cluster.local
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }  
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        resources:
-          # requests:
-          #   cpu: "100m"
-          #   memory: "50Mi"
-          # limits:
-          #   cpu: "4G"
-          #   memory: "4Gi"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-service
-spec:
-  selector:
-    run: otoroshi-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
haproxy.example -
-
-
frontend front_nodes_http
-    bind *:80
-    mode tcp
-    default_backend back_http_nodes
-    timeout client          1m
-
-frontend front_nodes_https
-    bind *:443
-    mode tcp
-    default_backend back_https_nodes
-    timeout client          1m
-
-backend back_http_nodes
-    mode tcp
-    balance roundrobin
-    server kubernetes-node1 10.2.2.40:41080
-    server kubernetes-node2 10.2.2.41:41080
-    server kubernetes-node3 10.2.2.42:41080
-    timeout connect        10s
-    timeout server          1m
-
-backend back_https_nodes
-    mode tcp
-    balance roundrobin
-    server kubernetes-node1 10.2.2.40:41443
-    server kubernetes-node2 10.2.2.41:41443
-    server kubernetes-node3 10.2.2.42:41443
-    timeout connect        10s
-    timeout server          1m
-
nginx.example -
-
-
stream {
-
-  upstream back_http_nodes {
-    zone back_http_nodes 64k;
-    server 10.2.2.40:41080 max_fails=1;
-    server 10.2.2.41:41080 max_fails=1;
-    server 10.2.2.42:41080 max_fails=1;
-  }
-
-  upstream back_https_nodes {
-    zone back_https_nodes 64k;
-    server 10.2.2.40:41443 max_fails=1;
-    server 10.2.2.41:41443 max_fails=1;
-    server 10.2.2.42:41443 max_fails=1;
-  }
-
-  server {
-    listen     80;
-    proxy_pass back_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     443;
-    proxy_pass back_https_nodes;
-    health_check;
-  }
-  
-}
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
-

Deploy an otoroshi cluster on a cloud provider managed kubernetes cluster

-

Here we have 2 replicas of an otoroshi leader connected to a redis instance and 2 replicas of an otoroshi worker connected to the leader. We use a service of type LoadBalancer to expose otoroshi leader/worker to the rest of the world. You have to setup your DNS to bind otoroshi domain names to the LoadBalancer external CNAME (see the example below)

-
-
deployment.yaml -
-
-
---
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-leader-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-leader-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-leader-deployment
-    replicas: 2
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-leader
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: CLUSTER_MODE
-            value: Leader
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-worker-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }        
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-worker-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-worker-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-worker-deployment
-    replicas: 2
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always   
-      containers:
-      - image: maif/otoroshi:1.5.11-dev
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-worker
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: CLUSTER_MODE
-            value: Worker
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-api-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-worker-service
-spec:
-  selector:
-    run: otoroshi-worker-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-external-service
-spec:
-  type: LoadBalancer
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 80
-    name: "http"
-    targetPort: "http"
-  - port: 443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-worker-external-service
-spec:
-  type: LoadBalancer
-  selector:
-    run: otoroshi-worker-deployment
-  ports:
-  - port: 80
-    name: "http"
-    targetPort: "http"
-  - port: 443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
dns.example -
-
-
otoroshi.your.otoroshi.domain      IN CNAME generated.cname.for.leader.of.your.cluster.loadbalancer
-otoroshi-api.your.otoroshi.domain  IN CNAME generated.cname.for.leader.of.your.cluster.loadbalancer
-privateapps.your.otoroshi.domain   IN CNAME generated.cname.for.leader.of.your.cluster.loadbalancer
-
-api1.another.domain                IN CNAME generated.cname.for.worker.of.your.cluster.loadbalancer
-api2.another.domain                IN CNAME generated.cname.for.worker.of.your.cluster.loadbalancer
-*.api.the.api.domain               IN CNAME generated.cname.for.worker.of.your.cluster.loadbalancer
-
-

Deploy an otoroshi cluster on a bare metal kubernetes cluster

-

Here we have 2 replicas of otoroshi leader connected to the same redis instance and 2 replicas for otoroshi worker. The otoroshi instances are exposed as nodePort so you’ll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below).

-
-
deployment.yaml -
-
-
---
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-leader-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-leader-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-leader-deployment
-    replicas: 2
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-leader
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: CLUSTER_MODE
-            value: Leader
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-worker-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }  
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-worker-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-worker-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-worker-deployment
-    replicas: 2
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always   
-      containers:
-      - image: maif/otoroshi:1.5.11-dev
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-worker
-        ports:
-          - containerPort: 8080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: CLUSTER_MODE
-            value: Worker
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-api-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    nodePort: 31080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    nodePort: 31443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-worker-service
-spec:
-  selector:
-    run: otoroshi-worker-deployment
-  ports:
-  - port: 8080
-    nodePort: 32080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    nodePort: 32443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
nginx.example -
-
-
stream {
-
-  upstream worker_http_nodes {
-    zone worker_http_nodes 64k;
-    server 10.2.2.40:32080 max_fails=1;
-    server 10.2.2.41:32080 max_fails=1;
-    server 10.2.2.42:32080 max_fails=1;
-  }
-
-  upstream worker_https_nodes {
-    zone worker_https_nodes 64k;
-    server 10.2.2.40:32443 max_fails=1;
-    server 10.2.2.41:32443 max_fails=1;
-    server 10.2.2.42:32443 max_fails=1;
-  }
-
-  upstream leader_http_nodes {
-    zone leader_http_nodes 64k;
-    server 10.2.2.40:31080 max_fails=1;
-    server 10.2.2.41:31080 max_fails=1;
-    server 10.2.2.42:31080 max_fails=1;
-  }
-
-  upstream leader_https_nodes {
-    zone leader_https_nodes 64k;
-    server 10.2.2.40:31443 max_fails=1;
-    server 10.2.2.41:31443 max_fails=1;
-    server 10.2.2.42:31443 max_fails=1;
-  }
-
-  server {
-    listen     80;
-    proxy_pass worker_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     443;
-    proxy_pass worker_https_nodes;
-    health_check;
-  }
-
-  server {
-    listen     81;
-    proxy_pass leader_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     444;
-    proxy_pass leader_https_nodes;
-    health_check;
-  }
-  
-}
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
-

Deploy an otoroshi cluster on a bare metal kubernetes cluster using DaemonSet

-

Here we have 1 otoroshi leader instance on each kubernetes node (with the otoroshi-kind: leader label) connected to the same redis instance and 1 otoroshi worker instance on each kubernetes node (with the otoroshi-kind: worker label). The otoroshi instances are exposed as nodePort so you’ll have to add a loadbalancer in front of your kubernetes nodes to route external traffic (TCP) to your otoroshi instances. You have to setup your DNS to bind otoroshi domain names to your loadbalancer (see the example below).

-
-
deployment.yaml -
-
-
---
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  name: otoroshi-leader-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-leader-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-leader-deployment
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      affinity:
-        nodeAffinity:
-          requiredDuringSchedulingIgnoredDuringExecution:
-            nodeSelectorTerms:
-            - matchExpressions:
-              - key: otoroshi-kind
-                operator: In
-                values:
-                - leader
-      tolerations:
-      - key: node-role.kubernetes.io/master
-        effect: NoSchedule
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always
-      containers:
-      - image: maif/otoroshi:1.5.11-jdk11
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-leader
-        ports:
-          - containerPort: 8080
-            hostPort: 41080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            hostPort: 41443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: APP_STORAGE
-            value: lettuce
-          - name: REDIS_URL
-            value: ${redisUrl}
-            # value: redis://redis-leader-service:6379/0
-          - name: CLUSTER_MODE
-            value: Leader
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: OTOROSHI_SECRET
-            value: ${otoroshiSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: OTOROSHI_INITIAL_CUSTOMIZATION
-            value: >
-              {
-                "config":{
-                  "tlsSettings": {
-                    "defaultDomain": "www.${domain}",
-                    "randomIfNotFound": false
-                  },
-                  "scripts":{
-                    "enabled":true,
-                    "sinkRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator",
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector"
-                    ],
-                    "sinkConfig": {},
-                    "jobRefs":[
-                      "cp:otoroshi.plugins.jobs.kubernetes.KubernetesOtoroshiCRDsControllerJob"
-                    ],
-                    "jobConfig":{
-                      "KubernetesConfig": {
-                        "trust": false,
-                        "namespaces": [
-                          "*"
-                        ],
-                        "labels": {},
-                        "namespacesLabels": {},
-                        "ingressClasses": [
-                          "otoroshi"
-                        ],
-                        "defaultGroup": "default",
-                        "ingresses": false,
-                        "crds": true,
-                        "coreDnsIntegration": false,
-                        "coreDnsIntegrationDryRun": false,
-                        "kubeLeader": false,
-                        "restartDependantDeployments": false,
-                        "watch": false,
-                        "syncDaikokuApikeysOnly": false,
-                        "kubeSystemNamespace": "kube-system",
-                        "coreDnsConfigMapName": "coredns",
-                        "coreDnsDeploymentName": "coredns",
-                        "corednsPort": 53,
-                        "otoroshiServiceName": "otoroshi-worker-service",
-                        "otoroshiNamespace": "${namespace}",
-                        "clusterDomain": "cluster.local",
-                        "syncIntervalSeconds": 60,
-                        "coreDnsEnv": null,
-                        "watchTimeoutSeconds": 60,
-                        "watchGracePeriodSeconds": 5,
-                        "mutatingWebhookName": "otoroshi-admission-webhook-injector",
-                        "validatingWebhookName": "otoroshi-admission-webhook-validation",
-                        "templates": {
-                          "service-group": {},
-                          "service-descriptor": {},
-                          "apikeys": {},
-                          "global-config": {},
-                          "jwt-verifier": {},
-                          "tcp-service": {},
-                          "certificate": {},
-                          "auth-module": {},
-                          "script": {},
-                          "organizations": {},
-                          "teams": {},
-                          "webhooks": {
-                            "flags": {
-                              "requestCert": true,
-                              "originCheck": true,
-                              "tokensCheck": true,
-                              "displayEnv": false,
-                              "tlsTrace": false
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }  
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  name: otoroshi-worker-deployment
-spec:
-  selector:
-    matchLabels:
-      run: otoroshi-worker-deployment
-  template:
-    metadata:
-      labels:
-        run: otoroshi-worker-deployment
-    replicas: 2
-    strategy:
-      type: RollingUpdate
-      rollingUpdate:
-        maxUnavailable: 1
-        maxSurge: 1
-    spec:
-      affinity:
-        nodeAffinity:
-          requiredDuringSchedulingIgnoredDuringExecution:
-            nodeSelectorTerms:
-            - matchExpressions:
-              - key: otoroshi-kind
-                operator: In
-                values:
-                - worker
-      tolerations:
-      - key: node-role.kubernetes.io/master
-        effect: NoSchedule
-      serviceAccountName: otoroshi-admin-user
-      terminationGracePeriodSeconds: 60
-      hostNetwork: false
-      restartPolicy: Always   
-      containers:
-      - image: maif/otoroshi:1.5.11-dev
-        imagePullPolicy: IfNotPresent
-        name: otoroshi-worker
-        ports:
-          - containerPort: 8080
-            hostPort: 42080
-            name: "http"
-            protocol: TCP
-          - containerPort: 8443
-            hostPort: 42443
-            name: "https"
-            protocol: TCP
-        env:
-          - name: APP_STORAGE_ROOT
-            value: otoroshi
-          - name: OTOROSHI_INITIAL_ADMIN_PASSWORD
-            value: ${password}
-          - name: APP_DOMAIN
-            value: ${domain}
-          - name: CLUSTER_MODE
-            value: Worker
-          - name: CLUSTER_AUTO_UPDATE_STATE
-            value: 'true'
-          - name: CLUSTER_MTLS_ENABLED
-            value: 'true'
-          - name: CLUSTER_MTLS_LOOSE
-            value: 'true'
-          - name: CLUSTER_MTLS_TRUST_ALL
-            value: 'true'
-          - name: CLUSTER_LEADER_URL
-            value: https://otoroshi-leader-api-service.${namespace}.svc.cluster.local:8443
-          - name: CLUSTER_LEADER_HOST
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN
-            value: otoroshi-leader-api-service.${namespace}.svc.cluster.local
-          - name: ADMIN_API_CLIENT_ID
-            value: ${clientId}
-          - name: CLUSTER_LEADER_CLIENT_ID
-            value: ${clientId}
-          - name: ADMIN_API_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: CLUSTER_LEADER_CLIENT_SECRET
-            value: ${clientSecret}
-          - name: HEALTH_LIMIT
-            value: "5000"
-          - name: SSL_OUTSIDE_CLIENT_AUTH
-            value: Want
-          - name: HTTPS_WANT_CLIENT_AUTH
-            value: "true"
-          - name: JAVA_OPTS
-            value: '-Xms2g -Xmx4g -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0'
-        readinessProbe:
-          httpGet:
-            path: /ready
-            port: 8080
-          failureThreshold: 1
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        livenessProbe:
-          httpGet:
-            path: /live
-            port: 8080
-          failureThreshold: 3
-          initialDelaySeconds: 60
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-api-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-leader-service
-spec:
-  selector:
-    run: otoroshi-leader-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-worker-service
-spec:
-  selector:
-    run: otoroshi-worker-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: otoroshi-service-certificate
-spec:
-  description: certificate for otoroshi-service
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - otoroshi-service
-    - otoroshi-service.${namespace}.svc.cluster.local
-    - otoroshi-api-service.${namespace}.svc.cluster.local
-    - otoroshi.${domain}
-    - otoroshi-api.${domain}
-    - privateapps.${domain}
-    key:
-      algo: rsa
-      size: 2048
-    subject: uid=otoroshi-service-cert, O=Otoroshi
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
nginx.example -
-
-
stream {
-
-  upstream worker_http_nodes {
-    zone worker_http_nodes 64k;
-    server 10.2.2.40:42080 max_fails=1;
-    server 10.2.2.41:42080 max_fails=1;
-    server 10.2.2.42:42080 max_fails=1;
-  }
-
-  upstream worker_https_nodes {
-    zone worker_https_nodes 64k;
-    server 10.2.2.40:42443 max_fails=1;
-    server 10.2.2.41:42443 max_fails=1;
-    server 10.2.2.42:42443 max_fails=1;
-  }
-
-  upstream leader_http_nodes {
-    zone leader_http_nodes 64k;
-    server 10.2.2.40:41080 max_fails=1;
-    server 10.2.2.41:41080 max_fails=1;
-    server 10.2.2.42:41080 max_fails=1;
-  }
-
-  upstream leader_https_nodes {
-    zone leader_https_nodes 64k;
-    server 10.2.2.40:41443 max_fails=1;
-    server 10.2.2.41:41443 max_fails=1;
-    server 10.2.2.42:41443 max_fails=1;
-  }
-
-  server {
-    listen     80;
-    proxy_pass worker_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     443;
-    proxy_pass worker_https_nodes;
-    health_check;
-  }
-
-  server {
-    listen     81;
-    proxy_pass leader_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     444;
-    proxy_pass leader_https_nodes;
-    health_check;
-  }
-  
-}
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
dns.example -
-
-
# if your loadbalancer is at ip address 10.2.2.50
-
-otoroshi.your.otoroshi.domain      IN A 10.2.2.50
-otoroshi-api.your.otoroshi.domain  IN A 10.2.2.50
-privateapps.your.otoroshi.domain   IN A 10.2.2.50
-api1.another.domain                IN A 10.2.2.50
-api2.another.domain                IN A 10.2.2.50
-*.api.the.api.domain               IN A 10.2.2.50
-
-

Using Otoroshi as an Ingress Controller

-

If you want to use Otoroshi as an Ingress Controller, just go to the danger zone, and in Global scripts add the job named Kubernetes Ingress Controller.

-

Then add the following configuration for the job (with your own tweaks of course)

-
{
-  "KubernetesConfig": {
-    "enabled": true,
-    "endpoint": "https://127.0.0.1:6443",
-    "token": "eyJhbGciOiJSUzI....F463SrpOehQRaQ",
-    "namespaces": [
-      "*"
-    ]
-  }
-}
-
-

the configuration can have the following values

-
{
-  "KubernetesConfig": {
-    "endpoint": "https://127.0.0.1:6443", // the endpoint to talk to the kubernetes api, optional
-    "token": "xxxx", // the bearer token to talk to the kubernetes api, optional
-    "userPassword": "user:password", // the user password tuple to talk to the kubernetes api, optional
-    "caCert": "/etc/ca.cert", // the ca cert file path to talk to the kubernetes api, optional
-    "trust": false, // trust any cert to talk to the kubernetes api, optional
-    "namespaces": ["*"], // the watched namespaces
-    "labels": ["label"], // the watched namespaces
-    "ingressClasses": ["otoroshi"], // the watched kubernetes.io/ingress.class annotations, can be *
-    "defaultGroup": "default", // the group to put services in otoroshi
-    "ingresses": true, // sync ingresses
-    "crds": false, // sync crds
-    "kubeLeader": false, // delegate leader election to kubernetes, to know where the sync job should run
-    "restartDependantDeployments": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments
-    "templates": { // template for entities that will be merged with kubernetes entities. can be "default" to use otoroshi default templates
-      "service-group": {},
-      "service-descriptor": {},
-      "apikeys": {},
-      "global-config": {},
-      "jwt-verifier": {},
-      "tcp-service": {},
-      "certificate": {},
-      "auth-module": {},
-      "data-exporter": {},
-      "script": {},
-      "organization": {},
-      "team": {},
-      "data-exporter": {}
-    }
-  }
-}
-
-

If endpoint is not defined, Otoroshi will try to get it from $KUBERNETES_SERVICE_HOST and $KUBERNETES_SERVICE_PORT. If token is not defined, Otoroshi will try to get it from the file at /var/run/secrets/kubernetes.io/serviceaccount/token. If caCert is not defined, Otoroshi will try to get it from the file at /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. If $KUBECONFIG is defined, endpoint, token and caCert will be read from the current context of the file referenced by it.

-

Now you can deploy your first service ;)

-

Deploy an ingress route

-

now let’s say you want to deploy an http service and route to the outside world through otoroshi

-
---
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: http-app-deployment
-spec:
-  selector:
-    matchLabels:
-      run: http-app-deployment
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        run: http-app-deployment
-    spec:
-      containers:
-      - image: kennethreitz/httpbin
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        ports:
-          - containerPort: 80
-            name: "http"
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: http-app-service
-spec:
-  ports:
-    - port: 8080
-      targetPort: http
-      name: http
-  selector:
-    run: http-app-deployment
----
-apiVersion: networking.k8s.io/v1beta1
-kind: Ingress
-metadata:
-  name: http-app-ingress
-  annotations:
-    kubernetes.io/ingress.class: otoroshi
-spec:
-  tls:
-  - hosts:
-    - httpapp.foo.bar
-    secretName: http-app-cert
-  rules:
-  - host: httpapp.foo.bar
-    http:
-      paths:
-      - path: /
-        backend:
-          serviceName: http-app-service
-          servicePort: 8080
-
-

once deployed, otoroshi will sync with kubernetes and create the corresponding service to route your app. You will be able to access your app with

-
curl -X GET https://httpapp.foo.bar/get
-
-

Support for Ingress Classes

-

Since Kubernetes 1.18, you can use IngressClass type of manifest to specify which ingress controller you want to use for a deployment (https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#extended-configuration-with-ingress-classes). Otoroshi is fully compatible with this new manifest kind. To use it, configure the Ingress job to match your controller

-
{
-  "KubernetesConfig": {
-    ...
-    "ingressClasses": ["otoroshi.io/ingress-controller"],
-    ...
-  }
-}
-
-

then you have to deploy an IngressClass to declare Otoroshi as an ingress controller

-
apiVersion: "networking.k8s.io/v1beta1"
-kind: "IngressClass"
-metadata:
-  name: "otoroshi-ingress-controller"
-spec:
-  controller: "otoroshi.io/ingress-controller"
-  parameters:
-    apiGroup: "proxy.otoroshi.io/v1alpha"
-    kind: "IngressParameters"
-    name: "otoroshi-ingress-controller"
-
-

and use it in your Ingress

-
apiVersion: networking.k8s.io/v1beta1
-kind: Ingress
-metadata:
-  name: http-app-ingress
-spec:
-  ingressClassName: otoroshi-ingress-controller
-  tls:
-  - hosts:
-    - httpapp.foo.bar
-    secretName: http-app-cert
-  rules:
-  - host: httpapp.foo.bar
-    http:
-      paths:
-      - path: /
-        backend:
-          serviceName: http-app-service
-          servicePort: 8080
-
-

Use multiple ingress controllers

-

It is of course possible to use multiple ingress controller at the same time (https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#using-multiple-ingress-controllers) using the annotation kubernetes.io/ingress.class. By default, otoroshi reacts to the class otoroshi, but you can make it the default ingress controller with the following config

-
{
-  "KubernetesConfig": {
-    ...
-    "ingressClass": "*",
-    ...
-  }
-}
-
-

Supported annotations

-

if you need to customize the service descriptor behind an ingress rule, you can use some annotations. If you need better customisation, just go to the CRDs part. The following annotations are supported :

-
    -
  • ingress.otoroshi.io/groups
  • -
  • ingress.otoroshi.io/group
  • -
  • ingress.otoroshi.io/groupId
  • -
  • ingress.otoroshi.io/name
  • -
  • ingress.otoroshi.io/targetsLoadBalancing
  • -
  • ingress.otoroshi.io/stripPath
  • -
  • ingress.otoroshi.io/enabled
  • -
  • ingress.otoroshi.io/userFacing
  • -
  • ingress.otoroshi.io/privateApp
  • -
  • ingress.otoroshi.io/forceHttps
  • -
  • ingress.otoroshi.io/maintenanceMode
  • -
  • ingress.otoroshi.io/buildMode
  • -
  • ingress.otoroshi.io/strictlyPrivate
  • -
  • ingress.otoroshi.io/sendOtoroshiHeadersBack
  • -
  • ingress.otoroshi.io/readOnly
  • -
  • ingress.otoroshi.io/xForwardedHeaders
  • -
  • ingress.otoroshi.io/overrideHost
  • -
  • ingress.otoroshi.io/allowHttp10
  • -
  • ingress.otoroshi.io/logAnalyticsOnServer
  • -
  • ingress.otoroshi.io/useAkkaHttpClient
  • -
  • ingress.otoroshi.io/useNewWSClient
  • -
  • ingress.otoroshi.io/tcpUdpTunneling
  • -
  • ingress.otoroshi.io/detectApiKeySooner
  • -
  • ingress.otoroshi.io/letsEncrypt
  • -
  • ingress.otoroshi.io/publicPatterns
  • -
  • ingress.otoroshi.io/privatePatterns
  • -
  • ingress.otoroshi.io/additionalHeaders
  • -
  • ingress.otoroshi.io/additionalHeadersOut
  • -
  • ingress.otoroshi.io/missingOnlyHeadersIn
  • -
  • ingress.otoroshi.io/missingOnlyHeadersOut
  • -
  • ingress.otoroshi.io/removeHeadersIn
  • -
  • ingress.otoroshi.io/removeHeadersOut
  • -
  • ingress.otoroshi.io/headersVerification
  • -
  • ingress.otoroshi.io/matchingHeaders
  • -
  • ingress.otoroshi.io/ipFiltering.whitelist
  • -
  • ingress.otoroshi.io/ipFiltering.blacklist
  • -
  • ingress.otoroshi.io/api.exposeApi
  • -
  • ingress.otoroshi.io/api.openApiDescriptorUrl
  • -
  • ingress.otoroshi.io/healthCheck.enabled
  • -
  • ingress.otoroshi.io/healthCheck.url
  • -
  • ingress.otoroshi.io/jwtVerifier.ids
  • -
  • ingress.otoroshi.io/jwtVerifier.enabled
  • -
  • ingress.otoroshi.io/jwtVerifier.excludedPatterns
  • -
  • ingress.otoroshi.io/authConfigRef
  • -
  • ingress.otoroshi.io/redirection.enabled
  • -
  • ingress.otoroshi.io/redirection.code
  • -
  • ingress.otoroshi.io/redirection.to
  • -
  • ingress.otoroshi.io/clientValidatorRef
  • -
  • ingress.otoroshi.io/transformerRefs
  • -
  • ingress.otoroshi.io/transformerConfig
  • -
  • ingress.otoroshi.io/accessValidator.enabled
  • -
  • ingress.otoroshi.io/accessValidator.excludedPatterns
  • -
  • ingress.otoroshi.io/accessValidator.refs
  • -
  • ingress.otoroshi.io/accessValidator.config
  • -
  • ingress.otoroshi.io/preRouting.enabled
  • -
  • ingress.otoroshi.io/preRouting.excludedPatterns
  • -
  • ingress.otoroshi.io/preRouting.refs
  • -
  • ingress.otoroshi.io/preRouting.config
  • -
  • ingress.otoroshi.io/issueCert
  • -
  • ingress.otoroshi.io/issueCertCA
  • -
  • ingress.otoroshi.io/gzip.enabled
  • -
  • ingress.otoroshi.io/gzip.excludedPatterns
  • -
  • ingress.otoroshi.io/gzip.whiteList
  • -
  • ingress.otoroshi.io/gzip.blackList
  • -
  • ingress.otoroshi.io/gzip.bufferSize
  • -
  • ingress.otoroshi.io/gzip.chunkedThreshold
  • -
  • ingress.otoroshi.io/gzip.compressionLevel
  • -
  • ingress.otoroshi.io/cors.enabled
  • -
  • ingress.otoroshi.io/cors.allowOrigin
  • -
  • ingress.otoroshi.io/cors.exposeHeaders
  • -
  • ingress.otoroshi.io/cors.allowHeaders
  • -
  • ingress.otoroshi.io/cors.allowMethods
  • -
  • ingress.otoroshi.io/cors.excludedPatterns
  • -
  • ingress.otoroshi.io/cors.maxAge
  • -
  • ingress.otoroshi.io/cors.allowCredentials
  • -
  • ingress.otoroshi.io/clientConfig.useCircuitBreaker
  • -
  • ingress.otoroshi.io/clientConfig.retries
  • -
  • ingress.otoroshi.io/clientConfig.maxErrors
  • -
  • ingress.otoroshi.io/clientConfig.retryInitialDelay
  • -
  • ingress.otoroshi.io/clientConfig.backoffFactor
  • -
  • ingress.otoroshi.io/clientConfig.connectionTimeout
  • -
  • ingress.otoroshi.io/clientConfig.idleTimeout
  • -
  • ingress.otoroshi.io/clientConfig.callAndStreamTimeout
  • -
  • ingress.otoroshi.io/clientConfig.callTimeout
  • -
  • ingress.otoroshi.io/clientConfig.globalTimeout
  • -
  • ingress.otoroshi.io/clientConfig.sampleInterval
  • -
  • ingress.otoroshi.io/enforceSecureCommunication
  • -
  • ingress.otoroshi.io/sendInfoToken
  • -
  • ingress.otoroshi.io/sendStateChallenge
  • -
  • ingress.otoroshi.io/secComHeaders.claimRequestName
  • -
  • ingress.otoroshi.io/secComHeaders.stateRequestName
  • -
  • ingress.otoroshi.io/secComHeaders.stateResponseName
  • -
  • ingress.otoroshi.io/secComTtl
  • -
  • ingress.otoroshi.io/secComVersion
  • -
  • ingress.otoroshi.io/secComInfoTokenVersion
  • -
  • ingress.otoroshi.io/secComExcludedPatterns
  • -
  • ingress.otoroshi.io/secComSettings.size
  • -
  • ingress.otoroshi.io/secComSettings.secret
  • -
  • ingress.otoroshi.io/secComSettings.base64
  • -
  • ingress.otoroshi.io/secComUseSameAlgo
  • -
  • ingress.otoroshi.io/secComAlgoChallengeOtoToBack.size
  • -
  • ingress.otoroshi.io/secComAlgoChallengeOtoToBack.secret
  • -
  • ingress.otoroshi.io/secComAlgoChallengeOtoToBack.base64
  • -
  • ingress.otoroshi.io/secComAlgoChallengeBackToOto.size
  • -
  • ingress.otoroshi.io/secComAlgoChallengeBackToOto.secret
  • -
  • ingress.otoroshi.io/secComAlgoChallengeBackToOto.base64
  • -
  • ingress.otoroshi.io/secComAlgoInfoToken.size
  • -
  • ingress.otoroshi.io/secComAlgoInfoToken.secret
  • -
  • ingress.otoroshi.io/secComAlgoInfoToken.base64
  • -
  • ingress.otoroshi.io/securityExcludedPatterns
  • -
-

for more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html

-

with the previous example, the ingress does not define any apikey, so the route is public. If you want to enable apikeys on it, you can deploy the following descriptor

-
apiVersion: networking.k8s.io/v1beta1
-kind: Ingress
-metadata:
-  name: http-app-ingress
-  annotations:
-    kubernetes.io/ingress.class: otoroshi
-    ingress.otoroshi.io/group: http-app-group
-    ingress.otoroshi.io/forceHttps: 'true'
-    ingress.otoroshi.io/sendOtoroshiHeadersBack: 'true'
-    ingress.otoroshi.io/overrideHost: 'true'
-    ingress.otoroshi.io/allowHttp10: 'false'
-    ingress.otoroshi.io/publicPatterns: ''
-spec:
-  tls:
-  - hosts:
-    - httpapp.foo.bar
-    secretName: http-app-cert
-  rules:
-  - host: httpapp.foo.bar
-    http:
-      paths:
-      - path: /
-        backend:
-          serviceName: http-app-service
-          servicePort: 8080
-
-

now you can use an existing apikey in the http-app-group to access your app

-
curl -X GET https://httpapp.foo.bar/get -u existing-apikey-1:secret-1
-
-

Use Otoroshi CRDs for a better/full integration

-

Otoroshi provides some Custom Resource Definitions for kubernetes in order to manage Otoroshi related entities in kubernetes

-
    -
  • service-groups
  • -
  • service-descriptors
  • -
  • apikeys
  • -
  • certificates
  • -
  • global-configs
  • -
  • jwt-verifiers
  • -
  • auth-modules
  • -
  • scripts
  • -
  • tcp-services
  • -
  • data-exporters
  • -
  • admins
  • -
  • teams
  • -
  • organizations
  • -
-

using CRDs, you will be able to deploy and manager those entities from kubectl or the kubernetes api like

-
sudo kubectl get apikeys --all-namespaces
-sudo kubectl get service-descriptors --all-namespaces
-curl -X GET \
-  -H 'Authorization: Bearer eyJhbGciOiJSUzI....F463SrpOehQRaQ' \
-  -H 'Accept: application/json' -k \
-  https://127.0.0.1:6443/apis/proxy.otoroshi.io/v1alpha1/apikeys | jq
-
-

You can see this as better Ingress resources. Like any Ingress resource can define which controller it uses (using the kubernetes.io/ingress.class annotation), you can chose another kind of resource instead of Ingress. With Otoroshi CRDs you can even define resources like Certificate, Apikey, AuthModules, JwtVerifier, etc. It will help you to use all the power of Otoroshi while using the deployment model of kubernetes.

Warning
-

when using Otoroshi CRDs, Kubernetes becomes the single source of truth for the synced entities. It means that any value in the descriptors deployed will overrides the one in Otoroshi datastore each time it’s synced. So be careful if you use the Otoroshi UI or the API, some changes in configuration may be overriden by CRDs sync job.

-

Resources examples

-
-
group.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ServiceGroup
-metadata:
-  name: http-app-group
-  annotations:
-    io.otoroshi/id: http-app-group
-spec:
-  description: a group to hold services about the http-app
-
apikey.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ApiKey
-metadata:
-  name: http-app-2-apikey-1
-# this apikey can be used to access another app in a different group
-spec:
-  # a secret name secret-1 will be created by otoroshi and can be used by containers
-  exportSecret: true 
-  secretName: secret-2
-  authorizedEntities: 
-  - http-app-2-group
-  metadata:
-    foo: bar
-  rotation: # not mandatory
-    enabled: true
-    rotationEvery: 720 # hours
-    gracePeriod: 168  # hours
-
service-descriptor.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ServiceDescriptor
-metadata:
-  name: http-app-service-descriptor
-spec:
-  description: the service descriptor for the http app
-  groups: 
-  - http-app-group
-  forceHttps: true
-  hosts:
-  - httpapp.foo.bar
-  matchingRoot: /
-  targets:
-  - url: 'https://http-app-service:8443'
-    # you can also use serviceName and servicePort to use pods ip addresses. Can be used without or in combination with url
-    # serviceName: http-app-service
-    # servicePort: https
-    mtlsConfig: # not mandatory
-      # use mtls to contact the backend
-      mtls: true
-      certs: 
-        # reference the DN for the client cert
-        - UID=httpapp-client, O=OtoroshiApps
-      trustedCerts: 
-        # reference the DN for the CA cert
-        - CN=Otoroshi Root
-  sendOtoroshiHeadersBack: true
-  xForwardedHeaders: true
-  overrideHost: true
-  allowHttp10: false
-  publicPatterns:
-    - /health
-  additionalHeaders:
-    x-foo: bar
-
certificate.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: http-app-certificate-client
-spec:
-  description: certificate for the http-app
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=httpapp-client, O=OtoroshiApps
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
-
jwt.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: JwtVerifier
-metadata:
-  name: http-app-verifier
-  annotations:
-    io.otoroshi/id: http-app-verifier
-spec:
-  desc: verify that the jwt token in header jwt is ok
-  strict: true
-  source:
-    type: InHeader
-    name: jwt
-    remove: ''
-  algoSettings:
-    type: HSAlgoSettings
-    size: 512
-    secret: secret
-  strategy:
-    type: PassThrough
-    verificationSettings:
-      fields: 
-        foo: bar
-      arrayFields: {}
-
auth.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: AuthModule
-metadata:
-  name: http-app-auth
-  annotations:
-    io.otoroshi/id: http-app-auth
-spec:
-  type: oauth2
-  desc: Keycloak mTLS
-  sessionMaxAge: 86400
-  clientId: otoroshi
-  clientSecret: ''
-  authorizeUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/auth'
-  tokenUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/token'
-  userInfoUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/userinfo'
-  introspectionUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/token/introspect'
-  loginUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/auth'
-  logoutUrl: 'https://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/logout'
-  scope: openid address email microprofile-jwt offline_access phone profile roles web-origins
-  claims: ''
-  useCookie: false
-  useJson: false
-  readProfileFromToken: false
-  accessTokenField: access_token
-  jwtVerifier:
-    type: JWKSAlgoSettings
-    url: 'http://keycloak.foo.bar/auth/realms/master/protocol/openid-connect/certs'
-    timeout: 2000
-    headers: {}
-    ttl: 3600000
-    kty: RSA
-    proxy: 
-    mtlsConfig:
-      certs: []
-      trustedCerts: []
-      mtls: false
-      loose: false
-      trustAll: false
-  nameField: email
-  emailField: email
-  apiKeyMetaField: apkMeta
-  apiKeyTagsField: apkTags
-  otoroshiDataField: app_metadata|otoroshi_data
-  callbackUrl: 'https://privateapps.oto.tools/privateapps/generic/callback'
-  oidConfig: 'http://keycloak.foo.bar/auth/realms/master/.well-known/openid-configuration'
-  mtlsConfig:
-    certs:
-    - UID=httpapp-client, O=OtoroshiApps
-    trustedCerts:
-    - UID=httpapp-client, O=OtoroshiApps
-    mtls: true
-    loose: false
-    trustAll: false
-  proxy: 
-  extraMetadata: {}
-  refreshTokens: false
-
organization.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Tenant
-metadata:
-  name: default-organization
-spec:
-  id: default
-  name: Default organization
-  description: Default organization created for any otoroshi instance
-  metadata: {}
-
team.yaml -
-
-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Team
-metadata:
-  name: default-team
-spec:
-  id: default
-  tenant: default
-  name: Default team
-  description: Default team created for any otoroshi instance
-  metadata: {}
-
-

Configuration

-

To configure it, just go to the danger zone, and in Global scripts add the job named Kubernetes Otoroshi CRDs Controller. Then add the following configuration for the job (with your own tweak of course)

-
{
-  "KubernetesConfig": {
-    "enabled": true,
-    "crds": true,
-    "endpoint": "https://127.0.0.1:6443",
-    "token": "eyJhbGciOiJSUzI....F463SrpOehQRaQ",
-    "namespaces": [
-      "*"
-    ]
-  }
-}
-
-

the configuration can have the following values

-
{
-  "KubernetesConfig": {
-    "endpoint": "https://127.0.0.1:6443", // the endpoint to talk to the kubernetes api, optional
-    "token": "xxxx", // the bearer token to talk to the kubernetes api, optional
-    "userPassword": "user:password", // the user password tuple to talk to the kubernetes api, optional
-    "caCert": "/etc/ca.cert", // the ca cert file path to talk to the kubernetes api, optional
-    "trust": false, // trust any cert to talk to the kubernetes api, optional
-    "namespaces": ["*"], // the watched namespaces
-    "labels": ["label"], // the watched namespaces
-    "ingressClasses": ["otoroshi"], // the watched kubernetes.io/ingress.class annotations, can be *
-    "defaultGroup": "default", // the group to put services in otoroshi
-    "ingresses": false, // sync ingresses
-    "crds": true, // sync crds
-    "kubeLeader": false, // delegate leader election to kubernetes, to know where the sync job should run
-    "restartDependantDeployments": true, // when a secret/cert changes from otoroshi sync, restart dependant deployments
-    "templates": { // template for entities that will be merged with kubernetes entities. can be "default" to use otoroshi default templates
-      "service-group": {},
-      "service-descriptor": {},
-      "apikeys": {},
-      "global-config": {},
-      "jwt-verifier": {},
-      "tcp-service": {},
-      "certificate": {},
-      "auth-module": {},
-      "data-exporter": {},
-      "script": {},
-      "organization": {},
-      "team": {},
-      "data-exporter": {}
-    }
-  }
-}
-
-

If endpoint is not defined, Otoroshi will try to get it from $KUBERNETES_SERVICE_HOST and $KUBERNETES_SERVICE_PORT. If token is not defined, Otoroshi will try to get it from the file at /var/run/secrets/kubernetes.io/serviceaccount/token. If caCert is not defined, Otoroshi will try to get it from the file at /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. If $KUBECONFIG is defined, endpoint, token and caCert will be read from the current context of the file referenced by it.

-

you can find a more complete example of the configuration object here

-

Note about apikeys and certificates resources

-

Apikeys and Certificates are a little bit different than the other resources. They have ability to be defined without their secret part, but with an export setting so otoroshi will generate the secret parts and export the apikey or the certificate to kubernetes secret. Then any app will be able to mount them as volumes (see the full example below)

-

In those resources you can define

-
exportSecret: true 
-secretName: the-secret-name
-
-

and omit clientSecret for apikey or publicKey, privateKey for certificates. For certificate you will have to provide a csr for the certificate in order to generate it

-
csr:
-  issuer: CN=Otoroshi Root
-  hosts: 
-  - httpapp.foo.bar
-  - httpapps.foo.bar
-  key:
-    algo: rsa
-    size: 2048
-  subject: UID=httpapp-front, O=OtoroshiApps
-  client: false
-  ca: false
-  duration: 31536000000
-  signatureAlg: SHA256WithRSAEncryption
-  digestAlg: SHA-256
-
-

when apikeys are exported as kubernetes secrets, they will have the type otoroshi.io/apikey-secret with values clientId and clientSecret

-
apiVersion: v1
-kind: Secret
-metadata:
-  name: apikey-1
-type: otoroshi.io/apikey-secret
-data:
-  clientId: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==
-  clientSecret: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==
-
-

when certificates are exported as kubernetes secrets, they will have the type kubernetes.io/tls with the standard values tls.crt (the full cert chain) and tls.key (the private key). For more convenience, they will also have a cert.crt value containing the actual certificate without the ca chain and ca-chain.crt containing the ca chain without the certificate.

-
apiVersion: v1
-kind: Secret
-metadata:
-  name: certificate-1
-type: kubernetes.io/tls
-data:
-  tls.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==
-  tls.key: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==
-  cert.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA==
-  ca-chain.crt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA== 
-
-

Full CRD example

-

then you can deploy the previous example with better configuration level, and using mtls, apikeys, etc

-

Let say the app looks like :

-
const fs = require('fs'); 
-const https = require('https'); 
-
-// here we read the apikey to access http-app-2 from files mounted from secrets
-const clientId = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientId').toString('utf8')
-const clientSecret = fs.readFileSync('/var/run/secrets/kubernetes.io/apikeys/clientSecret').toString('utf8')
-
-const backendKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/tls.key').toString('utf8')
-const backendCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/cert.crt').toString('utf8')
-const backendCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/backend/ca-chain.crt').toString('utf8')
-
-const clientKey = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/tls.key').toString('utf8')
-const clientCert = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/cert.crt').toString('utf8')
-const clientCa = fs.readFileSync('/var/run/secrets/kubernetes.io/certs/client/ca-chain.crt').toString('utf8')
-
-function callApi2() {
-  return new Promise((success, failure) => {
-    const options = { 
-      // using the implicit internal name (*.global.otoroshi.mesh) of the other service descriptor passing through otoroshi
-      hostname: 'http-app-service-descriptor-2.global.otoroshi.mesh',  
-      port: 433, 
-      path: '/', 
-      method: 'GET',
-      headers: {
-        'Accept': 'application/json',
-        'Otoroshi-Client-Id': clientId,
-        'Otoroshi-Client-Secret': clientSecret,
-      },
-      cert: clientCert,
-      key: clientKey,
-      ca: clientCa
-    }; 
-    let data = '';
-    const req = https.request(options, (res) => { 
-      res.on('data', (d) => { 
-        data = data + d.toString('utf8');
-      }); 
-      res.on('end', () => { 
-        success({ body: JSON.parse(data), res });
-      }); 
-      res.on('error', (e) => { 
-        failure(e);
-      }); 
-    }); 
-    req.end();
-  })
-}
-
-const options = { 
-  key: backendKey, 
-  cert: backendCert, 
-  ca: backendCa, 
-  // we want mtls behavior
-  requestCert: true, 
-  rejectUnauthorized: true
-}; 
-https.createServer(options, (req, res) => { 
-  res.writeHead(200, {'Content-Type': 'application/json'});
-  callApi2().then(resp => {
-    res.write(JSON.stringify{ ("message": `Hello to ${req.socket.getPeerCertificate().subject.CN}`, api2: resp.body })); 
-  });
-}).listen(433);
-
-

then, the descriptors will be :

-
---
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: http-app-deployment
-spec:
-  selector:
-    matchLabels:
-      run: http-app-deployment
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        run: http-app-deployment
-    spec:
-      containers:
-      - image: foo/http-app
-        imagePullPolicy: IfNotPresent
-        name: otoroshi
-        ports:
-          - containerPort: 443
-            name: "https"
-        volumeMounts:
-        - name: apikey-volume
-          # here you will be able to read apikey from files 
-          # - /var/run/secrets/kubernetes.io/apikeys/clientId
-          # - /var/run/secrets/kubernetes.io/apikeys/clientSecret
-          mountPath: "/var/run/secrets/kubernetes.io/apikeys"
-          readOnly: true
-        volumeMounts:
-        - name: backend-cert-volume
-          # here you will be able to read app cert from files 
-          # - /var/run/secrets/kubernetes.io/certs/backend/tls.crt
-          # - /var/run/secrets/kubernetes.io/certs/backend/tls.key
-          mountPath: "/var/run/secrets/kubernetes.io/certs/backend"
-          readOnly: true
-        - name: client-cert-volume
-          # here you will be able to read app cert from files 
-          # - /var/run/secrets/kubernetes.io/certs/client/tls.crt
-          # - /var/run/secrets/kubernetes.io/certs/client/tls.key
-          mountPath: "/var/run/secrets/kubernetes.io/certs/client"
-          readOnly: true
-      volumes:
-      - name: apikey-volume
-        secret:
-          # here we reference the secret name from apikey http-app-2-apikey-1
-          secretName: secret-2
-      - name: backend-cert-volume
-        secret:
-          # here we reference the secret name from cert http-app-certificate-backend
-          secretName: http-app-certificate-backend-secret
-      - name: client-cert-volume
-        secret:
-          # here we reference the secret name from cert http-app-certificate-client
-          secretName: http-app-certificate-client-secret
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: http-app-service
-spec:
-  ports:
-    - port: 8443
-      targetPort: https
-      name: https
-  selector:
-    run: http-app-deployment
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ServiceGroup
-metadata:
-  name: http-app-group
-  annotations:
-    otoroshi.io/id: http-app-group
-spec:
-  description: a group to hold services about the http-app
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ApiKey
-metadata:
-  name: http-app-apikey-1
-# this apikey can be used to access the app
-spec:
-  # a secret name secret-1 will be created by otoroshi and can be used by containers
-  exportSecret: true 
-  secretName: secret-1
-  authorizedEntities: 
-  - group_http-app-group
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ApiKey
-metadata:
-  name: http-app-2-apikey-1
-# this apikey can be used to access another app in a different group
-spec:
-  # a secret name secret-1 will be created by otoroshi and can be used by containers
-  exportSecret: true 
-  secretName: secret-2
-  authorizedEntities: 
-  - group_http-app-2-group
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: http-app-certificate-frontend
-spec:
-  description: certificate for the http-app on otorshi frontend
-  autoRenew: true
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - httpapp.foo.bar
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=httpapp-front, O=OtoroshiApps
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: http-app-certificate-backend
-spec:
-  description: certificate for the http-app deployed on pods
-  autoRenew: true
-  # a secret name http-app-certificate-backend-secret will be created by otoroshi and can be used by containers
-  exportSecret: true 
-  secretName: http-app-certificate-backend-secret
-  csr:
-    issuer: CN=Otoroshi Root
-    hosts: 
-    - http-app-service 
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=httpapp-back, O=OtoroshiApps
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: http-app-certificate-client
-spec:
-  description: certificate for the http-app
-  autoRenew: true
-  secretName: http-app-certificate-client-secret
-  csr:
-    issuer: CN=Otoroshi Root
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=httpapp-client, O=OtoroshiApps
-    client: false
-    ca: false
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ServiceDescriptor
-metadata:
-  name: http-app-service-descriptor
-spec:
-  description: the service descriptor for the http app
-  groups: 
-  - http-app-group
-  forceHttps: true
-  hosts:
-  - httpapp.foo.bar # hostname exposed oustide of the kubernetes cluster
-  # - http-app-service-descriptor.global.otoroshi.mesh # implicit internal name inside the kubernetes cluster 
-  matchingRoot: /
-  targets:
-  - url: https://http-app-service:8443
-    # alternatively, you can use serviceName and servicePort to use pods ip addresses
-    # serviceName: http-app-service
-    # servicePort: https
-    mtlsConfig:
-      # use mtls to contact the backend
-      mtls: true
-      certs: 
-        # reference the DN for the client cert
-        - UID=httpapp-client, O=OtoroshiApps
-      trustedCerts: 
-        # reference the DN for the CA cert 
-        - CN=Otoroshi Root
-  sendOtoroshiHeadersBack: true
-  xForwardedHeaders: true
-  overrideHost: true
-  allowHttp10: false
-  publicPatterns:
-    - /health
-  additionalHeaders:
-    x-foo: bar
-# here you can specify everything supported by otoroshi like jwt-verifiers, auth config, etc ... for more informations about it, just go to https://maif.github.io/otoroshi/swagger-ui/index.html
-
-

now with this descriptor deployed, you can access your app with a command like

-
CLIENT_ID=`kubectl get secret secret-1 -o jsonpath="{.data.clientId}" | base64 --decode`
-CLIENT_SECRET=`kubectl get secret secret-1 -o jsonpath="{.data.clientSecret}" | base64 --decode`
-curl -X GET https://httpapp.foo.bar/get -u "$CLIENT_ID:$CLIENT_SECRET"
-
-

Expose Otoroshi to outside world

-

If you deploy Otoroshi on a kubernetes cluster, the Otoroshi service is deployed as a loadbalancer (service type: LoadBalancer). You’ll need to declare in your DNS settings any name that can be routed by otoroshi going to the loadbalancer endpoint (CNAME or ip addresses) of your kubernetes distribution. If you use a managed kubernetes cluster from a cloud provider, it will work seamlessly as they will provide external loadbalancers out of the box. However, if you use a bare metal kubernetes cluster, id doesn’t come with support for external loadbalancers (service of type LoadBalancer). So you will have to provide this feature in order to route external TCP traffic to Otoroshi containers running inside the kubernetes cluster. You can use projects like MetalLB that provide software LoadBalancer services to bare metal clusters or you can use and customize examples in the installation section.

Warning
-

We don’t recommand running Otoroshi behind an existing ingress controller (or something like that) as you will not be able to use features like TCP proxying, TLS, mTLS, etc. Also, this additional layer of reverse proxy will increase call latencies.

-

Access a service from inside the k8s cluster

-

Using host header overriding

-

You can access any service referenced in otoroshi, through otoroshi from inside the kubernetes cluster by using the otoroshi service name (if you use a template based on https://github.com/MAIF/otoroshi/tree/master/kubernetes/base deployed in the otoroshi namespace) and the host header with the service domain like :

-
CLIENT_ID="xxx"
-CLIENT_SECRET="xxx"
-curl -X GET -H 'Host: httpapp.foo.bar' https://otoroshi-service.otoroshi.svc.cluster.local:8443/get -u "$CLIENT_ID:$CLIENT_SECRET"
-
-

Using dedicated services

-

it’s also possible to define services that targets otoroshi deployment (or otoroshi workers deployment) and use then as valid hosts in otoroshi services

-
apiVersion: v1
-kind: Service
-metadata:
-  name: my-awesome-service
-spec:
-  selector:
-    # run: otoroshi-deployment
-    # or in cluster mode
-    run: otoroshi-worker-deployment
-  ports:
-  - port: 8080
-    name: "http"
-    targetPort: "http"
-  - port: 8443
-    name: "https"
-    targetPort: "https"
-
-

and access it like

-
CLIENT_ID="xxx"
-CLIENT_SECRET="xxx"
-curl -X GET https://my-awesome-service.my-namspace.svc.cluster.local:8443/get -u "$CLIENT_ID:$CLIENT_SECRET"
-
-

Using coredns integration

-

You can also enable the coredns integration to simplify the flow. You can use the the following keys in the plugin config :

-
{
-  "KubernetesConfig": {
-    ...
-    "coreDnsIntegration": true,                // enable coredns integration for intra cluster calls
-    "kubeSystemNamespace": "kube-system",      // the namespace where coredns is deployed
-    "corednsConfigMap": "coredns",             // the name of the coredns configmap
-    "otoroshiServiceName": "otoroshi-service", // the name of the otoroshi service, could be otoroshi-workers-service
-    "otoroshiNamespace": "otoroshi",           // the namespace where otoroshi is deployed
-    "clusterDomain": "cluster.local",          // the domain for cluster services
-    ...
-  }
-}
-
-

otoroshi will patch coredns config at startup then you can call your services like

-
CLIENT_ID="xxx"
-CLIENT_SECRET="xxx"
-curl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u "$CLIENT_ID:$CLIENT_SECRET"
-
-

By default, all services created from CRDs service descriptors are exposed as ${service-name}.${service-namespace}.otoroshi.mesh or ${service-name}.${service-namespace}.svc.otoroshi.local

-

Using coredns with manual patching

-

you can also patch the coredns config manually

-
kubectl edit configmaps coredns -n kube-system # or your own custom config map
-
-

and change the Corefile data to add the following snippet in at the end of the file

-
otoroshi.mesh:53 {
-    errors
-    health
-    ready
-    kubernetes cluster.local in-addr.arpa ip6.arpa {
-        pods insecure
-        upstream
-        fallthrough in-addr.arpa ip6.arpa
-    }
-    rewrite name regex (.*)\.otoroshi\.mesh otoroshi-worker-service.otoroshi.svc.cluster.local
-    forward . /etc/resolv.conf
-    cache 30
-    loop
-    reload
-    loadbalance
-}
-
-

you can also define simpler rewrite if it suits you use case better

-
rewrite name my-service.otoroshi.mesh otoroshi-worker-service.otoroshi.svc.cluster.local
-
-

do not hesitate to change otoroshi-worker-service.otoroshi according to your own setup. If otoroshi is not in cluster mode, change it to otoroshi-service.otoroshi. If otoroshi is not deployed in the otoroshi namespace, change it to otoroshi-service.the-namespace, etc.

-

By default, all services created from CRDs service descriptors are exposed as ${service-name}.${service-namespace}.otoroshi.mesh

-

then you can call your service like

-
CLIENT_ID="xxx"
-CLIENT_SECRET="xxx"
-
-curl -X GET https://my-awesome-service.my-awesome-service-namespace.otoroshi.mesh:8443/get -u "$CLIENT_ID:$CLIENT_SECRET"
-
-

Using old kube-dns system

-

if your stuck with an old version of kubernetes, it uses kube-dns that is not supported by otoroshi, so you will have to provide your own coredns deployment and declare it as a stubDomain in the old kube-dns system.

-

Here is an example of coredns deployment with otoroshi domain config

-
-
coredns.yaml -
-
-
---
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-data:
-  Corefile: |
-    otoroshi.mesh:5353 {
-        errors
-        health
-        ready
-        kubernetes cluster.local in-addr.arpa ip6.arpa {
-            pods insecure
-            fallthrough in-addr.arpa ip6.arpa
-        }
-        rewrite name regex (.*)\.otoroshi\.mesh otoroshi-service.otoroshi.svc.cluster.local
-        forward . /etc/resolv.conf
-        cache 30
-        loop
-        reload
-        loadbalance
-    }
-    .:5353 {
-        errors
-        health
-        kubernetes cluster.local in-addr.arpa ip6.arpa {
-          pods insecure
-          fallthrough in-addr.arpa ip6.arpa
-        }
-        forward . /etc/resolv.conf
-        cache 30
-        loop
-        reload
-        loadbalance
-    }
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-spec:
-  # clusterIP: 1.1.1.1
-  selector:
-    app: otoroshi
-    component: coredns
-  type: ClusterIP
-  ports:
-    - name: dns
-      port: 5353
-      protocol: UDP
-    - name: dns-tcp
-      port: 5353
-      protocol: TCP
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-spec:
-  replicas: 2
-  strategy:
-    type: RollingUpdate
-    rollingUpdate:
-      maxUnavailable: 1
-  selector:
-    matchLabels:
-      app: otoroshi
-      component: coredns
-  template:
-    metadata:
-      labels:
-        app: otoroshi
-        component: coredns
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      affinity:
-        podAntiAffinity:
-          preferredDuringSchedulingIgnoredDuringExecution:
-            - weight: 100
-              podAffinityTerm:
-                labelSelector:
-                  matchExpressions:
-                    - key: app
-                      operator: In
-                      values:
-                        - otoroshi
-                    - key: component
-                      operator: In
-                      values:
-                        - coredns
-                topologyKey: "kubernetes.io/hostname"
-      tolerations:
-        - key: "CriticalAddonsOnly"
-          operator: "Exists"
-      containers:
-        - name: coredns
-          image: coredns/coredns:1.8.0
-          imagePullPolicy: IfNotPresent
-          resources:
-            limits:
-              memory: 170Mi
-            requests:
-              cpu: 100m
-              memory: 70Mi
-          args: [ "-conf", "/etc/coredns/Corefile" ]
-          volumeMounts:
-            - name: config-volume
-              mountPath: /etc/coredns
-              readOnly: true
-          ports:
-            - containerPort: 5353
-              name: dns
-              protocol: UDP
-            - containerPort: 5353
-              name: dns-tcp
-              protocol: TCP
-          securityContext:
-          allowPrivilegeEscalation: false
-          capabilities:
-            add:
-            - NET_BIND_SERVICE
-            drop:
-            - all
-          readOnlyRootFilesystem: true
-          livenessProbe:
-            httpGet:
-              path: /health
-              port: 8080
-              scheme: HTTP
-            initialDelaySeconds: 30
-            timeoutSeconds: 5
-            successThreshold: 1
-            failureThreshold: 5
-      dnsPolicy: Default
-      volumes:
-        - name: config-volume
-          configMap:
-            name: otoroshi-dns
-            items:
-              - key: Corefile
-                path: Corefile
-  
-
-

then you can enable the kube-dns integration in the otoroshi kubernetes job

-
{
-  "KubernetesConfig": {
-    ...
-    "kubeDnsOperatorIntegration": true,                // enable kube-dns integration for intra cluster calls
-    "kubeDnsOperatorCoreDnsNamespace": "otoroshi",    // namespace where coredns is installed
-    "kubeDnsOperatorCoreDnsName": "otoroshi-dns",     // name of the coredns service
-    "kubeDnsOperatorCoreDnsPort": 5353,               // port of the coredns service
-    ...
-  }
-}
-
-

Using Openshift DNS operator

-

Openshift DNS operator does not allow to customize DNS configuration a lot, so you will have to provide your own coredns deployment and declare it as a stub in the Openshift DNS operator.

-

Here is an example of coredns deployment with otoroshi domain config

-
-
coredns.yaml -
-
-
---
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-data:
-  Corefile: |
-    otoroshi.mesh:5353 {
-        errors
-        health
-        ready
-        kubernetes cluster.local in-addr.arpa ip6.arpa {
-            pods insecure
-            fallthrough in-addr.arpa ip6.arpa
-        }
-        rewrite name regex (.*)\.otoroshi\.mesh otoroshi-service.otoroshi.svc.cluster.local
-        forward . /etc/resolv.conf
-        cache 30
-        loop
-        reload
-        loadbalance
-    }
-    .:5353 {
-        errors
-        health
-        kubernetes cluster.local in-addr.arpa ip6.arpa {
-          pods insecure
-          fallthrough in-addr.arpa ip6.arpa
-        }
-        forward . /etc/resolv.conf
-        cache 30
-        loop
-        reload
-        loadbalance
-    }
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-spec:
-  # clusterIP: 1.1.1.1
-  selector:
-    app: otoroshi
-    component: coredns
-  type: ClusterIP
-  ports:
-    - name: dns
-      port: 5353
-      protocol: UDP
-    - name: dns-tcp
-      port: 5353
-      protocol: TCP
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: otoroshi-dns
-  labels:
-    app: otoroshi
-    component: coredns
-spec:
-  replicas: 2
-  strategy:
-    type: RollingUpdate
-    rollingUpdate:
-      maxUnavailable: 1
-  selector:
-    matchLabels:
-      app: otoroshi
-      component: coredns
-  template:
-    metadata:
-      labels:
-        app: otoroshi
-        component: coredns
-    spec:
-      serviceAccountName: otoroshi-admin-user
-      affinity:
-        podAntiAffinity:
-          preferredDuringSchedulingIgnoredDuringExecution:
-            - weight: 100
-              podAffinityTerm:
-                labelSelector:
-                  matchExpressions:
-                    - key: app
-                      operator: In
-                      values:
-                        - otoroshi
-                    - key: component
-                      operator: In
-                      values:
-                        - coredns
-                topologyKey: "kubernetes.io/hostname"
-      tolerations:
-        - key: "CriticalAddonsOnly"
-          operator: "Exists"
-      containers:
-        - name: coredns
-          image: coredns/coredns:1.8.0
-          imagePullPolicy: IfNotPresent
-          resources:
-            limits:
-              memory: 170Mi
-            requests:
-              cpu: 100m
-              memory: 70Mi
-          args: [ "-conf", "/etc/coredns/Corefile" ]
-          volumeMounts:
-            - name: config-volume
-              mountPath: /etc/coredns
-              readOnly: true
-          ports:
-            - containerPort: 5353
-              name: dns
-              protocol: UDP
-            - containerPort: 5353
-              name: dns-tcp
-              protocol: TCP
-          securityContext:
-          allowPrivilegeEscalation: false
-          capabilities:
-            add:
-            - NET_BIND_SERVICE
-            drop:
-            - all
-          readOnlyRootFilesystem: true
-          livenessProbe:
-            httpGet:
-              path: /health
-              port: 8080
-              scheme: HTTP
-            initialDelaySeconds: 30
-            timeoutSeconds: 5
-            successThreshold: 1
-            failureThreshold: 5
-      dnsPolicy: Default
-      volumes:
-        - name: config-volume
-          configMap:
-            name: otoroshi-dns
-            items:
-              - key: Corefile
-                path: Corefile
-  
-
-

then you can enable the Openshift DNS operator integration in the otoroshi kubernetes job

-
{
-  "KubernetesConfig": {
-    ...
-    "openshiftDnsOperatorIntegration": true,                // enable openshift dns operator integration for intra cluster calls
-    "openshiftDnsOperatorCoreDnsNamespace": "otoroshi",    // namespace where coredns is installed
-    "openshiftDnsOperatorCoreDnsName": "otoroshi-dns",     // name of the coredns service
-    "openshiftDnsOperatorCoreDnsPort": 5353,               // port of the coredns service
-    ...
-  }
-}
-
-

don’t forget to update the otoroshi ClusterRole

-
- apiGroups:
-    - operator.openshift.io
-  resources:
-    - dnses
-  verbs:
-    - get
-    - list
-    - watch
-    - update
-
-

CRD validation in kubectl

-

In order to get CRD validation before manifest deployments right inside kubectl, you can deploy a validation webhook that will do the trick. Also check that you have otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookCRDValidator request sink enabled.

-
-
validation-webhook.yaml -
-
-
apiVersion: admissionregistration.k8s.io/v1
-kind: ValidatingWebhookConfiguration
-metadata:
-  name: otoroshi-admission-webhook-validation
-  labels:
-    app: otoroshi
-    component: otoroshi-validation-webhook
-webhooks:
-  - name: otoroshi-admission-webhook.otoroshi.io
-    rules:
-      - operations: 
-          - "CREATE"
-          - "UPDATE"
-        apiGroups: 
-          - "proxy.otoroshi.io"
-        apiVersions: 
-          - "*"
-        resources: 
-          - "*"
-        scope: "Namespaced"
-    clientConfig:
-      # url: "https://otoroshi-kubernetes-admission-webhook.otoroshi.svc.cluster.local:8443/apis/webhooks/validation"
-      service:
-        name: otoroshi-service
-        namespace: otoroshi
-        path: "/apis/webhooks/validation"
-        port: 8443
-      caBundle: "" # injected at runtime
-    failurePolicy: Ignore # inject at runtime
-    sideEffects: None
-    admissionReviewVersions: 
-      - "v1"
-
-

Easier integration with otoroshi-sidecar

-

Otoroshi can help you to easily use existing services without modifications while gettings all the perks of otoroshi like apikeys, mTLS, exchange protocol, etc. To do so, otoroshi will inject a sidecar container in the pod of your deployment that will handle call coming from otoroshi and going to otoroshi. To enable otoroshi-sidecar, you need to deploy the following admission webhook. Also check that you have otoroshi.plugins.jobs.kubernetes.KubernetesAdmissionWebhookSidecarInjector request sink enabled.

-
-
sidecar-webhook.yaml -
-
-
apiVersion: admissionregistration.k8s.io/v1
-kind: MutatingWebhookConfiguration
-metadata:
-  name: otoroshi-admission-webhook-injector
-  labels:
-    app: otoroshi
-    component: otoroshi-validation-webhook
-webhooks:
-  - name: otoroshi-admission-webhook-injector.otoroshi.io
-    rules:
-      - operations: 
-          - "CREATE" 
-        apiGroups: 
-          - ""
-        apiVersions: 
-          - "v1"
-        resources: 
-          - "pods"
-        scope: "Namespaced"
-    # namespaceSelector:
-    #   matchLabels:
-    #     otoroshi.io/sidecar: inject
-    objectSelector:
-      matchLabels:
-        otoroshi.io/sidecar: inject
-    clientConfig:
-      # url: "https://otoroshi-kubernetes-admission-webhook.otoroshi.svc.cluster.local:8443/apis/webhooks/inject"
-      service:
-        name: otoroshi-service
-        namespace: otoroshi
-        path: "/apis/webhooks/inject"
-        port: 8443
-      caBundle: "" # inject at runtime
-    failurePolicy: Ignore # inject at runtime
-    sideEffects: None
-    admissionReviewVersions: 
-      - "v1"
-
-

then it’s quite easy to add the sidecar, just add the following label to your pod otoroshi.io/sidecar: inject and some annotations to tell otoroshi what certificates and apikeys to use.

-
annotations:
-  otoroshi.io/sidecar-apikey: backend-apikey
-  otoroshi.io/sidecar-backend-cert: backend-cert
-  otoroshi.io/sidecar-client-cert: oto-client-cert
-  otoroshi.io/token-secret: secret
-  otoroshi.io/expected-dn: UID=oto-client-cert, O=OtoroshiApps
-
-

now you can just call you otoroshi handled apis from inside your pod like curl http://my-service.namespace.otoroshi.mesh/api without passing any apikey or client certificate and the sidecar will handle everything for you. Same thing for call from otoroshi to your pod, everything will be done in mTLS fashion with apikeys and otoroshi exchange protocol

-

here is a full example

-
-
sidecar.yaml -
-
-
---
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: app-deployment
-spec:
-  selector:
-    matchLabels:
-      run: app-deployment
-      app: node
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        run: app-deployment
-        app: node
-        foo: bar
-        otoroshi.io/sidecar: inject
-      annotations:
-        otoroshi.io/sidecar-apikey: backend-apikey
-        otoroshi.io/sidecar-backend-cert: backend-cert
-        otoroshi.io/sidecar-client-cert: oto-client-cert
-        otoroshi.io/token-secret: secret
-        otoroshi.io/expected-dn: UID=oto-client-cert, O=OtoroshiApps
-    spec:
-      containers:
-      - image: containous/whoami:latest
-        name: whoami
-        args: ["--port", "8081"]
-        ports:
-          - name: main-port
-            containerPort: 8081
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: app-service
-spec:
-  selector:
-    run: app-deployment
-  ports:
-  - port: 8443
-    name: "https"
-    targetPort: "https"
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: backend-cert
-spec:
-  description: backend-cert
-  autoRenew: true
-  exportSecret: true 
-  secretName: backend-cert
-  csr:
-    hosts:
-      - app-service.default.svc.cluster.local
-    issuer: otoroshi-intermediate-ca
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=backend-cert, O=OtoroshiApps
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: client-cert
-  annotations:
-    otoroshi.io/id: client-cert
-spec:
-  description: client-cert
-  autoRenew: true
-  exportSecret: true
-  client: true
-  secretName: client-cert
-  csr:
-    client: true
-    issuer: otoroshi-intermediate-ca
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=client-cert, O=OtoroshiApps
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: oto-client-cert
-  annotations:
-    otoroshi.io/id: oto-client-cert
-spec:
-  description: oto-client-cert
-  autoRenew: true
-  exportSecret: true
-  client: true
-  secretName: oto-client-cert
-  csr:
-    client: true
-    issuer: otoroshi-intermediate-ca
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=oto-client-cert, O=OtoroshiApps
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: frontend-cert
-spec:
-  description: frontend-cert
-  autoRenew: true
-  csr:
-    issuer: otoroshi-intermediate-ca
-    hosts:
-      - backend.oto.tools
-    key:
-      algo: rsa
-      size: 2048
-    subject: UID=frontend-cert, O=OtoroshiApps
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: Certificate
-metadata:
-  name: mesh-cert
-spec:
-  description: mesh-cert
-  autoRenew: true
-  csr:
-    issuer: otoroshi-intermediate-ca
-    hosts:
-      - '*.default.otoroshi.mesh'
-    key:
-      algo: rsa
-      size: 2048
-    subject: O=Otoroshi, OU=Otoroshi Certificates, CN=kubernetes-mesh
-    duration: 31536000000
-    signatureAlg: SHA256WithRSAEncryption
-    digestAlg: SHA-256
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ApiKey
-metadata:
-  name: backend-apikey
-spec:
-  exportSecret: true 
-  secretName: backend-apikey
-  authorizedEntities:
-    - group_default
----
-apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ServiceDescriptor
-metadata:
-  name: backend
-spec:
-  description: backend
-  groups: 
-  - default
-  forceHttps: false
-  hosts:
-  - backend.oto.tools
-  matchingRoot: /
-  publicPatterns:
-    - /.*
-  secComUseSameAlgo: true
-  secComVersion: 2
-  secComInfoTokenVersion: Latest
-  secComSettings:
-    type: HSAlgoSettings
-    size: 512
-    secret: secret
-    base64: false
-  secComAlgoChallengeOtoToBack:
-    type: HSAlgoSettings
-    size: 512
-    secret: secret
-    base64: false
-  secComAlgoChallengeBackToOto:
-    type: HSAlgoSettings
-    size: 512
-    secret: secret
-    base64: false
-  secComAlgoInfoToken:
-    type: HSAlgoSettings
-    size: 512
-    secret: secret
-    base64: false
-  targets:
-  - url: https://app-service.default.svc.cluster.local:8443
-    mtlsConfig:
-      mtls: true
-      certs: 
-        - UID=oto-client-cert, O=OtoroshiApps
-      trustedCerts: 
-        - otoroshi-intermediate-ca
-
Warning
-

Please avoid to use port 80 for your pod as it’s the default port to access otoroshi from your pod and the call will be redirect to the sidecar via an iptables rule

-

Daikoku integration

-

It is possible to easily integrate daikoku generated apikeys without any human interaction with the actual apikey secret. To do that, create a plan in Daikoku and setup the integration mode to Automatic

-
-

then when a user subscribe for an apikey, he will only see an integration token

-
-

then just create an ApiKey manifest with this token and your good to go

-
apiVersion: proxy.otoroshi.io/v1alpha1
-kind: ApiKey
-metadata:
-  name: http-app-2-apikey-3
-spec:
-  exportSecret: true 
-  secretName: secret-3
-  daikokuToken: RShQrvINByiuieiaCBwIZfGFgdPu7tIJEN5gdV8N8YeH4RI9ErPYJzkuFyAkZ2xy
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/deploy/scaling.html b/docs/manual/deploy/scaling.html deleted file mode 100644 index 71e2b75aec..0000000000 --- a/docs/manual/deploy/scaling.html +++ /dev/null @@ -1,609 +0,0 @@ - - - - -Scaling Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Scaling Otoroshi

-

Using multiple instances with a front load balancer

-

Otoroshi has been designed to work with multiple instances. If you already have an infrastructure using frontal load balancing, you just have to declare Otoroshi instances as the target of all domain names handled by Otoroshi

-

Using master / workers mode of Otoroshi

-

You can read everything about it in the clustering section of the documentation.

-

Using IPVS

-

You can use IPVS to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi. You can find example of configuration here

-

Using DNS Round Robin

-

You can use DNS round robin technique to declare multiple A records under the domain names handled by Otoroshi.

-

Using software L4/L7 load balancers

-

You can use software L4 load balancers like NGINX or HAProxy to load balance layer 4 traffic directly from the Linux Kernel to multiple instances of Otoroshi.

-
-
NGINX L7
-
-
upstream otoroshi {
-  server 192.168.1.40:8080 max_fails=1;
-  server 192.168.1.41:8080 max_fails=1;
-  server 192.168.1.42:8080 max_fails=1;
-}
-
-server {
-  listen 80;
-  # http://nginx.org/en/docs/http/server_names.html
-  server_name otoroshi.oto.tools otoroshi-api.oto.tools otoroshi-admin-internal-api.oto.tools privateapps.oto.tools *-api.oto.tools;
-  location / {
-    # SSE config
-    proxy_buffering off;
-    proxy_cache off;
-    proxy_set_header Connection '';
-    proxy_http_version 1.1;
-    chunked_transfer_encoding off;
-  
-    # websockets config
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-  
-    # other config
-    proxy_set_header Host $http_host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_pass http://otoroshi;
-  }
-}
-
-server {
-  listen 443 ssl;
-  # http://nginx.org/en/docs/http/server_names.html
-  server_name otoroshi.oto.tools otoroshi-api.oto.tools otoroshi-admin-internal-api.oto.tools privateapps.oto.tools *-api.oto.tools;
-  ssl_certificate           /etc/letsencrypt/wildcard.oto.tools/fullchain.pem;
-  ssl_certificate_key       /etc/letsencrypt/wildcard.oto.tools/privkey.pem;
-  ssl_session_cache         shared:SSL:10m;
-  ssl_session_timeout       5m;
-  ssl_prefer_server_ciphers on;
-  ssl_ciphers               ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
-  ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
-  location / {
-    # SSE config
-    proxy_buffering off;
-    proxy_cache off;
-    proxy_set_header Connection '';
-    proxy_http_version 1.1;
-    chunked_transfer_encoding off;
-  
-    # websockets config
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-  
-    # other config
-    proxy_set_header Host $http_host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_pass http://otoroshi;
-  }
-}
-
NGINX L4
-
-
stream {
-
-  upstream back_http_nodes {
-    zone back_http_nodes 64k;
-    server 192.168.1.40:8080 max_fails=1;
-    server 192.168.1.41:8080 max_fails=1;
-    server 192.168.1.42:8080 max_fails=1;
-  }
-
-  upstream back_https_nodes {
-    zone back_https_nodes 64k;
-    server 192.168.1.40:8443 max_fails=1;
-    server 192.168.1.41:8443 max_fails=1;
-    server 192.168.1.42:8443 max_fails=1;
-  }
-
-  server {
-    listen     80;
-    proxy_pass back_http_nodes;
-    health_check;
-  }
-
-  server {
-    listen     443;
-    proxy_pass back_https_nodes;
-    health_check;
-  }
-  
-}
-
-
HA Proxy L7
-
-
frontend front_nodes_http
-    bind *:80
-    mode http
-    default_backend back_http_nodes
-    timeout client          1m
-
-frontend front_nodes_https
-    bind *:443
-    mode http
-    default_backend back_https_nodes
-    timeout client          1m
-
-backend back_http_nodes
-    mode http
-    balance roundrobin
-    option forwardfor
-    http-request set-header X-Forwarded-Port %[dst_port]
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
-    http-request set-header X-Client-IP %[src]
-    server node1 192.168.1.40:8080
-    server node2 192.168.1.41:8080
-    server node3 192.168.1.42:8080
-    timeout connect        10s
-    timeout server          1m
-
-backend back_https_nodes
-    mode http
-    balance roundrobin
-    option forwardfor
-    http-request set-header X-Forwarded-Port %[dst_port]
-    http-request add-header X-Forwarded-Proto https if { ssl_fc }
-    http-request set-header X-Client-IP %[src]
-    server node1 192.168.1.40:8443
-    server node2 192.168.1.41:8443
-    server node3 192.168.1.42:8443
-    timeout connect        10s
-    timeout server          1m
-
HA Proxy L4
-
-
frontend front_nodes_http
-    bind *:80
-    mode tcp
-    default_backend back_http_nodes
-    timeout client          1m
-
-frontend front_nodes_https
-    bind *:443
-    mode tcp
-    default_backend back_https_nodes
-    timeout client          1m
-
-backend back_http_nodes
-    mode tcp
-    balance roundrobin
-    server node1 192.168.1.40:8080
-    server node2 192.168.1.41:8080
-    server node3 192.168.1.42:8080
-    timeout connect        10s
-    timeout server          1m
-
-backend back_https_nodes
-    mode tcp
-    balance roundrobin
-    server node1 192.168.1.40:8443
-    server node2 192.168.1.41:8443
-    server node3 192.168.1.42:8443
-    timeout connect        10s
-    timeout server          1m
-
-

Using a custom TCP load balancer

-

You can also use any other TCP load balancer, from a hardware box to a small js file like

-
-
tcp-proxy.js -
-
-
const proxy = require("node-tcp-proxy");
-
-const hosts = ["192.168.1.40", "192.168.1.41", "192.168.1.42"];
-const portsHttp = [8080, 8080, 8080];
-const portsHttps = [8443, 8443, 8443];
-
-const proxyHttp = proxy.createProxy(80, hosts, portsHttp, {
-  tls: false
-});
-
-const proxyHttps = proxy.createProxy(443, hosts, portsHttps, {
-  tls: false
-});
-
-
tcp-proxy.rs -
-
-
extern crate futures;
-extern crate tokio;
-extern crate rand;
-
-use futures::{Future, Stream};
-use rand::Rng;
-use std::net::SocketAddr;
-use tokio::io::copy;
-use tokio::net::{TcpListener, TcpStream};
-use tokio::prelude::*;
-
-fn main() -> Result<(), Box<std::error::Error>> {
-    let urls: Vec<std::net::SocketAddr> = vec![
-        std::net::SocketAddr::new("192.168.1.40".parse().unwrap(), 8080),
-        std::net::SocketAddr::new("192.168.1.41".parse().unwrap(), 8080),
-        std::net::SocketAddr::new("192.168.1.42".parse().unwrap(), 8080),
-    ];
-    let addr: SocketAddr = "0.0.0.0:80".to_string().parse().unwrap();
-    let sock = TcpListener::bind(&addr).unwrap();
-    println!("TCP load balancer listening on {}", addr);
-    let done = sock
-        .incoming()
-        .map_err(move |e| println!("Error accepting socket; error = {:?}", e))
-        .for_each(move |server_socket| {
-            let index = rand::thread_rng().gen_range(0, urls.len());
-            let url = &urls[index];
-            let client_pair = TcpStream::connect(&url).map(|socket| socket.split());
-            let msg = client_pair
-                .and_then(move |(client_reader, client_writer)| {
-                    let (server_reader, server_writer) = server_socket.split();
-                    let upload = copy(server_reader, client_writer);
-                    let download = copy(client_reader, server_writer);
-                    upload.join(download)
-                }).then(|_res| {
-                    Ok(())
-                });
-            tokio::spawn(msg);
-            Ok(())
-        });
-    tokio::run(done);
-    Ok(())
-}
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/dev.html b/docs/manual/dev.html deleted file mode 100644 index 3ee580f500..0000000000 --- a/docs/manual/dev.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - -Developing Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Developing Otoroshi

-

If you want to play with Otoroshis code, here are some tips

-

The tools

-

You will need

-
    -
  • git
  • -
  • JDK 11
  • -
  • SBT 1.3.x
  • -
  • Node 13 + yarn 1.x
  • -
-

Clone the repository

-
git clone https://github.com/MAIF/otoroshi.git
-
-

or fork otoroshi and clone your own repository.

-

Run otoroshi in dev mode

-

to run otoroshi in dev mode, you’ll need to run two separate process to serve the javascript UI and the server part.

-

Javascript side

-

just go to <repo>/otoroshi/javascript and install the dependencies with

-
yarn install
-# or
-npm install
-
-

then run the dev server with

-
yarn start
-# or
-npm run start
-
-

Server side

-

setup SBT opts with

-
export SBT_OPTS="-Xmx2G -Xss6M"
-
-

then just go to <repo>/otoroshi and run the sbt console with

-
sbt
-
-

then in the sbt console run the following command

-
~run -Dotoroshi.storage=file -Dotoroshi.liveJs=true -Dhttps.port=9998 -Dotoroshi.privateapps.port=9999 -Dotoroshi.adminPassword=password -Dotoroshi.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dotoroshi.events.maxSize=0
-
-

or you can use the sbt-revolver to run otoroshi locally for a more prod alike behavior (on the TLS part for instance)

-
~reStart
-# to pass jvm args, you can use: ~reStart --- -Dotoroshi.storage=memory ...
-
-

you can now access your otoroshi instance at http://otoroshi.oto.tools:9999

-

Test otoroshi

-

to run otoroshi test just go to <repo>/otoroshi and run the main test suite with

-
sbt 'testOnly OtoroshiTests'
-
-

Create a release

-

just go to <repo>/otoroshi/javascript and then build the UI

-
yarn install
-yarn build
-
-

then go to <repo>/otoroshi and build the otoroshi distribution

-
sbt ';clean;compile;dist;assembly'
-
-

the otoroshi build is waiting for you in <repo>/otoroshi/target/scala-2.12/otoroshi.jar or <repo>/otoroshi/target/universal/otoroshi-1.x.x.zip

-

Build the documentation

-

from the root of your repository run

-
sh ./scripts/doc.sh all
-
-

The documentation is located at manual/target/paradox/site/main/

-

Format the sources

-

from the root of your repository run

-
sh ./scripts/fmt.sh
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/apikeys.html b/docs/manual/entities/apikeys.html deleted file mode 100644 index f5f768eb30..0000000000 --- a/docs/manual/entities/apikeys.html +++ /dev/null @@ -1,425 +0,0 @@ - - - - -Apikeys · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Apikeys

-

An API key is linked to one or more service group and service descriptor to allow you to access any service descriptor linked or contained in one of the linked service group. You can, of course, create multiple API key for given service groups/service descriptors.

-
-

You can found a concrete example here

-
    -
  • ApiKey Id: the id is a unique random key that will represent this API key
  • -
  • ApiKey Secret: the secret is a random key used to validate the API key
  • -
  • ApiKey Name: a name for the API key, used for debug purposes
  • -
  • ApiKey description: a useful description for this apikey
  • -
  • Valid until: auto disable apikey after this date
  • -
  • Enabled: if the API key is disabled, then any call using this API key will fail
  • -
  • Read only: if the API key is in read only mode, every request done with this api key will only work for GET, HEAD, OPTIONS verbs
  • -
  • Allow pass by clientid only: here you allow client to only pass client id in a specific header in order to grant access to the underlying api
  • -
  • Constrained services only: this apikey can only be used on services using apikey routing constraints
  • -
  • Authorized on: the groups/services linked to this api key
  • -
-

Metadata and tags

-
    -
  • Tags: tags attached to the api key
  • -
  • Metadata: metadata attached to the api key
  • -
-

Automatic secret rotation

-

API can handle automatic secret rotation by themselves. When enabled, the rotation changes the secret every Rotation every duration. During the Grace period both secret will be usable.

-
    -
  • Enabled: enabled automatic apikey secret rotation
  • -
  • Rotation every: rotate secrets every
  • -
  • Grace period: period when both secrets can be used
  • -
  • Next client secret: display the next generated client secret
  • -
-

Restrictions

-
    -
  • Enabled: enable restrictions
  • -
  • Allow last: Otoroshi will test forbidden and notFound paths before testing allowed paths
  • -
  • Allowed: allowed paths
  • -
  • Forbidden: forbidden paths
  • -
  • Not Found: not found paths
  • -
-

Call examples

-
    -
  • Curl Command: simple request with the api key passed by header
  • -
  • Basic Auth. Header: authorization Header with the api key as base64 encoded format
  • -
  • Curl Command with Basic Auth. Header: simple request with api key passed in the Authorization header as base64 format
  • -
-

Quotas

-
    -
  • Throttling quota: the authorized number of calls per second
  • -
  • Daily quota: the authorized number of calls per day
  • -
  • Monthly quota: the authorized number of calls per month
  • -
Warning
-

Daily and monthly quotas are based on the following rules :

-
    -
  • daily quota is computed between 00h00:00.000 and 23h59:59.999 of the current day
  • -
  • monthly qutoas is computed between the first day of the month at 00h00:00.000 and the last day of the month at 23h59:59.999
  • -
-

Quotas consumption

-
    -
  • Consumed daily calls: the number of calls consumed today
  • -
  • Remaining daily calls: the remaining number of calls for today
  • -
  • Consumed monthly calls: the number of calls consumed this month
  • -
  • Remaining monthly calls: the remaining number of calls for this month
  • -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/auth-modules.html b/docs/manual/entities/auth-modules.html deleted file mode 100644 index 7bf68528ab..0000000000 --- a/docs/manual/entities/auth-modules.html +++ /dev/null @@ -1,574 +0,0 @@ - - - - -Authentication modules · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Authentication modules

-

The authentication modules are the resources to manage the the access to Otoroshi UI and to protect a service.

-

An authentication module can be as well use on guard to access to the Otoroshi UI as to protect an app.

-

A private app is an Otoroshi service with an authentication module.

-

The list of supported authentication are :

-
    -
  • OAuth 2.0/2.1 : an authorization standard that allows a user to grant limited access to their resources on one site to another site, without having to expose their credentials
  • -
  • OAuth 1.0a : the original standard for access delegation
  • -
  • In memory : create users directly in Otoroshi with rights and metadata
  • -
  • LDAP : Lightweight Directory Access Protocol : connect users using a set of LDAP servers
  • -
  • SAML V2 - Security Assertion Markup Language : an open-standard, XML-based data format that allows businesses to communicate user authentication and authorization information to partner companies and enterprise applications their employees may use.
  • -
-

All authentication modules have a unique id, a name and a description.

-

Each module has also the following fields :

-
    -
  • Tags: list of tags associated to the module
  • -
  • Metadata: list of metadata associated to the module
  • -
  • HttpOnly: if enabled, the cookie cannot be accessed through client side script, prevent cross-site scripting (XSS) by not revealing the cookie to a third party
  • -
  • Secure: if enabled, avoid to include cookie in an HTTP Request without secure channel, typically HTTPs.
  • -
  • Session max. age: duration until the session expired
  • -
  • User validators: a list of validator that will check if a user that successfully logged in has the right to actually pass otoroshi based on the content of it’s profile. A validator is composed of a JSONPath that will tell what to check and a value that is the expected value. The JSONPath will be applied on a document that will look like
  • -
-
{
-    "_loc": {
-        "tenant": "default",
-        "teams": [
-            "default"
-        ]
-    },
-    "randomId": "xxxxx",
-    "name": "john.doe@otoroshi.io",
-    "email": "john.doe@otoroshi.io",
-    "authConfigId": "xxxxxxxx",
-    "profile": { // the profile shape depends heavily on the identity provider
-        "sub": "xxxxxx",
-        "nickname": "john.doe",
-        "name": "john.doe@otoroshi.io",
-        "picture": "https://foo.bar/avatar.png",
-        "updated_at": "2022-04-20T12:57:39.723Z",
-        "email": "john.doe@otoroshi.io",
-        "email_verified": true,
-        "rights": ["one", "two"]
-    },
-    "token": { // the token shape depends heavily on the identity provider
-        "access_token": "xxxxxx",
-        "refresh_token": "yyyyyy",
-        "id_token": "zzzzzz",
-        "scope": "openid profile email address phone offline_access",
-        "expires_in": 86400,
-        "token_type": "Bearer"
-    },
-    "realm": "global-oauth-xxxxxxx",
-    "otoroshiData": {
-        ...
-    },
-    "createdAt": 1650459462650,
-    "expiredAt": 1650545862652,
-    "lastRefresh": 1650459462650,
-    "metadata": {},
-    "tags": []
-}
-
-

the expected value support some syntax tricks like

-
    -
  • Not(value) on a string to check if the current value does not equals another value
  • -
  • Regex(regex) on a string to check if the current value matches the regex
  • -
  • RegexNot(regex) on a string to check if the current value does not matches the regex
  • -
  • Wildcard(*value*) on a string to check if the current value matches the value with wildcards
  • -
  • WildcardNot(*value*) on a string to check if the current value does not matches the value with wildcards
  • -
  • Contains(value) on a string to check if the current value contains a value
  • -
  • ContainsNot(value) on a string to check if the current value does not contains a value
  • -
  • Contains(Regex(regex)) on an array to check if one of the item of the array matches the regex
  • -
  • ContainsNot(Regex(regex)) on an array to check if one of the item of the array does not matches the regex
  • -
  • Contains(Wildcard(*value*)) on an array to check if one of the item of the array matches the wildcard value
  • -
  • ContainsNot(Wildcard(*value*)) on an array to check if one of the item of the array does not matches the wildcard value
  • -
  • Contains(value) on an array to check if the array contains a value
  • -
  • ContainsNot(value) on an array to check if the array does not contains a value
  • -
-

for instance to check if the current user has the right two, you can write the following validator

-
{
-  "path": "$.profile.rights",
-  "value": "Contains(two)"
-}
-
-

OAuth 2.0 / OIDC provider

-

If you want to secure an app or your Otoroshi UI with this provider, you can check these tutorials : Secure an app with keycloak or Secure an app with auth0

-
    -
  • Use cookie: If your OAuth2 provider does not support query param in redirect uri, you can use cookies instead
  • -
  • Use json payloads: the access token, sended to retrieve the user info, will be pass in body as JSON. If disabled, it will sended as Map.
  • -
  • Enabled PKCE flow: This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.
  • -
  • Disable wildcard on redirect URIs: As of OAuth 2.1, query parameters on redirect URIs are no longer allowed
  • -
  • Refresh tokens: Automatically refresh access token using the refresh token if available
  • -
  • Read profile from token: if enabled, the user profile will be read from the access token, otherwise the user profile will be retrieved from the user information url
  • -
  • Super admins only: All logged in users will have super admins rights
  • -
  • Client ID: a public identifier of your app
  • -
  • Client Secret: a secret known only to the application and the authorization server
  • -
  • Authorize URL: used to interact with the resource owner and get the authorization to access the protected resource
  • -
  • Token URL: used by the application in order to get an access token or a refresh token
  • -
  • Introspection URL: used to validate access tokens
  • -
  • Userinfo URL: used to retrieve the profile of the user
  • -
  • Login URL: used to redirect user to the login provider page
  • -
  • Logout URL: redirect uri used by the identity provider to redirect user after logging out
  • -
  • Callback URL: redirect uri sended to the identity provider to redirect user after successfully connecting
  • -
  • Access token field name: field used to search access token in the response body of the token URL call
  • -
  • Scope: presented scopes to the user in the consent screen. Scopes are space-separated lists of identifiers used to specify what access privileges are being requested
  • -
  • Claims: asked name/values pairs that contains information about a user.
  • -
  • Name field name: Retrieve name from token field
  • -
  • Email field name: Retrieve email from token field
  • -
  • Otoroshi metadata field name: Retrieve metadata from token field
  • -
  • Otoroshi rights field name: Retrieve user rights from user profile
  • -
  • Extra metadata: merged with the user metadata
  • -
  • Data override: merged with extra metadata when a user connects to a private app
  • -
  • Rights override: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.
  • -
  • Api key metadata field name: used to extract api key metadata from the OIDC access token
  • -
  • Api key tags field name: used to extract api key tags from the OIDC access token
  • -
  • Proxy host: host of proxy behind the identify provider
  • -
  • Proxy port: port of proxy behind the identify provider
  • -
  • Proxy principal: user of proxy
  • -
  • Proxy password: password of proxy
  • -
  • OIDC config url: URI of the openid-configuration used to discovery documents. By convention, this URI ends with .well-known/openid-configuration
  • -
  • Token verification: What kind of algorithm you want to use to verify/sign your JWT token with
  • -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • Hmac secret: The Hmac secret
  • -
  • Base64 encoded secret: Is the secret encoded with base64
  • -
  • Custom TLS Settings: TLS settings for JWKS fetching
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • Trust all: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with JWKS server
  • -
  • Trusted certificates: list of trusted certificates received from JWKS server
  • -
-

OAuth 1.0a provider

-

If you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : Secure an app with OAuth 1.0a

-
    -
  • Http Method: method used to get request token and the access token
  • -
  • Consumer key: the identifier portion of the client credentials (equivalent to a username)
  • -
  • Consumer secret: the identifier portion of the client credentials (equivalent to a password)
  • -
  • Request Token URL: url to retrieve the request token
  • -
  • Authorize URL: used to redirect user to the login page
  • -
  • Access token URL: used to retrieve the access token from the server
  • -
  • Profile URL: used to get the user profile
  • -
  • Callback URL: used to redirect user when successfully connecting
  • -
  • Rights override: override the rights of the connected user. With JSON format, each authenticated user, using email, can be associated to a list of rights on tenants and Otoroshi teams.
  • -
-

LDAP Authentication provider

-

If you want to secure an app or your Otoroshi UI with this provider, you can check this tutorial : Secure an app with LDAP

-
    -
  • Basic auth.: if enabled, user and password will be extract from the Authorization header as a Basic authentication. It will skipped the login Otoroshi page
  • -
  • Allow empty password: LDAP servers configured by default with the possibility to connect without password can be secured by this module to ensure that user provides a password
  • -
  • Super admins only: All logged in users will have super admins rights
  • -
  • Extract profile: extract LDAP profile in the Otoroshi user
  • -
  • LDAP Server URL: list of LDAP servers to join. Otoroshi use this list in sequence and swap to the next server, each time a server breaks in timeout
  • -
  • Search Base: used to global filter
  • -
  • Users search base: concat with search base to search users in LDAP
  • -
  • Mapping group filter: map LDAP groups with Otoroshi rights
  • -
  • Search Filter: used to filter users. ${username} is replace by the email of the user and compare to the given field
  • -
  • Admin username (bind DN): holds the name of the environment property for specifying the identity of the principal for authenticating the caller to the service
  • -
  • Admin password: holds the name of the environment property for specifying the credentials of the principal for authenticating the caller to the service
  • -
  • Extract profile filters attributes in: keep only attributes which are matching the regex
  • -
  • Extract profile filters attributes not in: keep only attributes which are not matching the regex
  • -
  • Name field name: Retrieve name from LDAP field
  • -
  • Email field name: Retrieve email from LDAP field
  • -
  • Otoroshi metadata field name: Retrieve metadata from LDAP field
  • -
  • Extra metadata: merged with the user metadata
  • -
  • Data override: merged with extra metadata when a user connects to a private app
  • -
  • Additional rights group: list of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.
  • -
  • Rights override: useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.
  • -
-

In memory provider

-
    -
  • Basic auth.: if enabled, user and password will be extract from the Authorization header as a Basic authentication. It will skipped the login Otoroshi page
  • -
  • Login with WebAuthn : enabled logging by WebAuthn
  • -
  • Users: list of users with name, email and metadata. The default password is password. The edit button is useful when you want to change the password of the user. The reset button reinitialize the password.
  • -
  • Users raw: show the registered users with their profile and their rights. You can edit directly each field, especially the rights of the user.
  • -
-

SAML v2 provider

-
    -
  • Single sign on URL: the Identity Provider Single Sign-On URL
  • -
  • The protocol binding for the login request: the protocol binding for the login request
  • -
  • Single Logout URL: a SAML flow that allows the end-user to logout from a single session and be automatically logged out of all related sessions that were established during SSO
  • -
  • The protocol binding for the logout request: the protocol binding for the logout request
  • -
  • Sign documents: Should SAML Request be signed by Otoroshi ?
  • -
  • Validate Assertions Signature: Enable/disable signature validation of SAML assertions
  • -
  • Validate assertions with Otoroshi certificate: validate assertions with Otoroshi certificate. If disabled, the Encryption Certificate and Encryption Private Key fields can be used to pass a certificate and a private key to validate assertions.
  • -
  • Encryption Certificate: certificate used to verify assertions
  • -
  • Encryption Private Key: privaye key used to verify assertions
  • -
  • Signing Certificate: certicate used to sign documents
  • -
  • Signing Private Key: private key to sign documents
  • -
  • Signature al: the signature algorithm to use to sign documents
  • -
  • Canonicalization Method: canonicalization method for XML signatures
  • -
  • Encryption KeyPair: the keypair used to sign/verify assertions
  • -
  • Name ID Format: SP and IdP usually communicate each other about a subject. That subject should be identified through a NAME-IDentifier, which should be in some format so that It is easy for the other party to identify it based on the Format
  • -
  • Use NameID format as email: use NameID format as email. If disabled, the email will be search from the attributes
  • -
  • URL issuer: provide the URL to the IdP’s who will issue the security token
  • -
  • Validate Signature: enable/disable signature validation of SAML responses
  • -
  • Validate Assertions Signature: should SAML Assertions to be decrypted ?
  • -
  • Validating Certificates: the certificate in PEM format that must be used to check for signatures.
  • -
-

Special routes

-

when using private apps with auth. modules, you can access special routes that can help you

-
GET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/logout' # trigger logout for the current auth. module
-GET 'http://xxxxxxxx.xxxx.xx/.well-known/otoroshi/me'     # get the current logged user profile (do not forget to pass cookies)
-
-

Related pages

- - -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/certificates.html b/docs/manual/entities/certificates.html deleted file mode 100644 index 5eb4c2a58e..0000000000 --- a/docs/manual/entities/certificates.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - -Certificates · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Certificates

-

All generated and imported certificates are listed in the https://otoroshi.xxxx/bo/dashboard/certificates page. All those certificates can be used to serve traffic with TLS, perform mTLS calls, sign and verify JWT tokens.

-

The list of available actions are:

-
    -
  • Add item: redirects the user on the certificate creation page. It’s useful when you already had a certificate (like a pem file) and that you want to load it in Otoroshi.
  • -
  • Let's Encrypt certificate: asks a certificate matching a given host to Let’s encrypt
  • -
  • Create certificate: issues a certificate with an existing Otoroshi certificate as CA.
  • -
  • Import .p12 file: loads a p12 file as certificate
  • -
-

Add item

-
    -
  • Id: the generated unique id of the certificate
  • -
  • Name: the name of the certificate
  • -
  • Description: the description of the certificate
  • -
  • Auto renew cert.: certificate will be issued when it will be expired. Only works with a CA from Otoroshi and a known private key
  • -
  • Client cert.: the certificate generated will be used to identicate a client to a server
  • -
  • Keypair: the certificate entity will be a pair of public key and private key.
  • -
  • Public key exposed: if true, the public key will be exposed on http://otoroshi-api.your-domain/.well-known/jwks.json
  • -
  • Certificate status: the current status of the certificate. It can be valid if the certificate is not revoked and not expired, or equal to the reason of the revocation
  • -
  • Certificate full chain: list of certificates used to authenticate a client or a server
  • -
  • Certificate private key: the private key of the certificate or nothing if wanted. You can omit it if you want just add a certificte full chain to trust them.
  • -
  • Private key password: the password to protect the private key
  • -
  • Certificate tags: the tags attached to the certificate
  • -
  • Certaificate metadata: the metadata attached to the certificate
  • -
-

Let’s Encrypt certificate

-
    -
  • Let's encrypt: if enabled, the certificate will be generated by Let’s Encrypt. If disabled, the user will be redirect to the Create certificate page
  • -
  • Host: the host send to Let’s encrypt to issue the certificate
  • -
-

Create certificate view

-
    -
  • Issuer: the CA used to sign your certificate
  • -
  • CA certificate: if enabled, the certificate will be used as an authority certificate. Once generated, it will be use as CA to sign the new certificates
  • -
  • Let's Encrypt: redirects to the Let’s Encrypt page to request a certificate
  • -
  • Client certificate: the certificate generated will be used to identicate a client to a server
  • -
  • Include A.I.A: include authority information access urls in the certificate
  • -
  • Key Type: the type of the private key
  • -
  • Key Size: the size of the private key
  • -
  • Signature Algorithm: the signature algorithm used to sign the certificate
  • -
  • Digest Algorithm: the digest algorithm used
  • -
  • Validity: how much time your certificate will be valid
  • -
  • Subject DN: the subject DN of your certificate
  • -
  • Hosts: the hosts of your certificate
  • -
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/data-exporters.html b/docs/manual/entities/data-exporters.html deleted file mode 100644 index 8915bfc278..0000000000 --- a/docs/manual/entities/data-exporters.html +++ /dev/null @@ -1,554 +0,0 @@ - - - - -Data exporters · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Data exporters

-

The data exporters are the way to export alerts and events from Otoroshi to an external storage.

-

To try them, you can folllow this tutorial.

-

Common fields

-
    -
  • Type: the type of event exporter
  • -
  • Enabled: enabled or not the exporter
  • -
  • Name: given name to the exporter
  • -
  • Description: the data exporter description
  • -
  • Tags: list of tags associated to the module
  • -
  • Metadata: list of metadata associated to the module
  • -
-

All exporters are split in three parts. The first and second parts are common and the last are specific by exporter.

-
    -
  • Filtering and projection : section to filter the list of sent events and alerts. The projection field allows you to export only certain event fields and reduce the size of exported data. It’s composed of Filtering and Projection fields. To get a full usage of this elements, read this section
  • -
  • Queue details: set of fields to adjust the workers of the exporter.
  • -
  • Buffer size: if elements are pushed onto the queue faster than the source is consumed the overflow will be handled with a strategy specified by the user. Keep in memory the number of events.
  • -
  • JSON conversion workers: number of workers used to transform events to JSON format in paralell
  • -
  • Send workers: number of workers used to send transformed events
  • -
  • Group size: chunk up this stream into groups of elements received within a time window (the time window is the next field)
  • -
  • Group duration: waiting time before sending the group of events. If the group size is reached before the group duration, the events will be instantly sent
  • -
-

For the last part, the Exporter configuration will be detail individually.

-

Matching and projections

-

Filtering is used to include or exclude some kind of events and alerts. For each include and exclude field, you can add a list of key-value.

-

Let’s say we only want to keep Otoroshi alerts

-
{ "include": [{ "@type": "AlertEvent" }] }
-
-

Otoroshi provides a list of rules to keep only events with specific values. We will use the following event to illustrate.

-
{
- "foo": "bar",
- "type": "AlertEvent",
- "alert": "big-alert",
- "status": 200,
- "codes": ["a", "b"],
- "inner": {
-   "foo": "bar",
-   "bar": "foo"
- }
-}
-
-

The rules apply with the previous example as event.

-

 

-

Projection is a list of fields to export. In the case of an empty list, all the fields of an event will be exported. In other case, only the listed fields will be exported.

-

Let’s say we only want to keep Otoroshi alerts and only type, timestamp and id of each exported events

-
{
- "@type": true,
- "@timestamp": true,
- "@id": true
-}
-
-

An other possibility is to rename the exported field. This value will be the same but the exported field will have a different name.

-

Let’s say we want to rename all @id field with unique-id as key

-
{ "@id": "unique-id" }
-
-

The last possiblity is to retrieve a sub-object of an event. Let’s say we want to get the name of each exported user of events.

-
{ "user": { "name": true } }
-
-

You can also expand the entire source object with

-
{
-  "$spread": true
-}
-
-

and the remove fields you don’t want with

-
{
-  "fieldthatidontwant": false
-}
-
-

Elastic

-

With this kind of exporter, every matching event will be sent to an elastic cluster (in batch). It is quite useful and can be used in combination with elastic read in global config

-
    -
  • Cluster URI: Elastic cluster URI
  • -
  • Index: Elastic index
  • -
  • Type: Event type (not needed for elasticsearch above 6.x)
  • -
  • User: Elastic User (optional)
  • -
  • Password: Elastic password (optional)
  • -
  • Version: Elastic version (optional, if none provided it will be fetched from cluster)
  • -
  • Apply template: Automatically apply index template
  • -
  • Check Connection: Button to test the configuration. It will displayed a modal with checked point, and if the case of it’s successfull, it will displayed the found version of the Elasticsearch and the index used
  • -
  • Manually apply index template: try to put the elasticsearch template by calling the api of elasticsearch
  • -
  • Show index template: try to retrieve the current index template presents in elasticsearch
  • -
  • Client side temporal indexes handling: When enabled, Otoroshi will manage the creation of indexes. When it’s disabled, Otoroshi will push in the same index
  • -
  • One index per: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch
  • -
  • Custom TLS Settings: Enable the TLS configuration for the communication with Elasticsearch
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • TrustAll: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with elasticsearch
  • -
  • Trusted certificates: list of trusted certificates received from elasticsearch
  • -
-

Webhook

-

With this kind of exporter, every matching event will be sent to a URL (in batch) using a POST method and an JSON array body.

-
    -
  • Alerts hook URL: url used to post events
  • -
  • Hook Headers: headers add to the post request
  • -
  • Custom TLS Settings: Enable the TLS configuration for the communication with Elasticsearch
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • TrustAll: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with elasticsearch
  • -
  • Trusted certificates: list of trusted certificates received from elasticsearch
  • -
-

Pulsar

-

With this kind of exporter, every matching event will be sent to an Apache Pulsar topic

-
    -
  • Pulsar URI: URI of the pulsar server
  • -
  • Custom TLS Settings: Enable the TLS configuration for the communication with Elasticsearch
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • TrustAll: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with elasticsearch
  • -
  • Trusted certificates: list of trusted certificates received from elasticsearch
  • -
  • Pulsar tenant: tenant on the pulsar server
  • -
  • Pulsar namespace: namespace on the pulsar server
  • -
  • Pulsar topic: topic on the pulsar server
  • -
-

Kafka

-

With this kind of exporter, every matching event will be sent to an Apache Kafka topic

-
    -
  • Kafka Servers: the list of servers to contact to connect the Kafka client with the Kafka cluster
  • -
  • Kafka keypass: the keystore password if you use a keystore/truststore to connect to Kafka cluster
  • -
  • Kafka keystore path: the keystore path on the server if you use a keystore/truststore to connect to Kafka cluster
  • -
  • Kafka truststore path: the truststore path on the server if you use a keystore/truststore to connect to Kafka cluster
  • -
  • Custom TLS Settings: enable the TLS configuration for the communication with Elasticsearch
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • TrustAll: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with elasticsearch
  • -
  • Trusted certificates: list of trusted certificates received from elasticsearch
  • -
  • Kafka topic: the topic on which Otoroshi alerts will be sent
  • -
-

Mailer

-

With this kind of exporter, every matching event will be sent in batch as an email (using one of the following email provider)

-

Otoroshi supports 5 exporters of email type.

-

Console

-

Nothing to add. The events will be write on the standard output.

-

Generic

-
    -
  • Mailer url: URL used to push events
  • -
  • Headers: headers add to the push requests
  • -
  • Email addresses: recipients of the emails
  • -
-

Mailgun

-
    -
  • EU: is EU server ? if enabled, *https://api.eu.mailgun.net/* will be used, otherwise, the US URL will be used : *https://api.mailgun.net/* -
  • -
  • Mailgun api key: API key of the mailgun account
  • -
  • Mailgun domain: domain name of the mailgun account
  • -
  • Email addresses: recipients of the emails
  • -
-

Mailjet

-
    -
  • Public api key: public key of the mailjet account
  • -
  • Private api key: private key of the mailjet account
  • -
  • Email addresses: recipients of the emails
  • -
-

Sendgrid

-
    -
  • Sendgrid api key: api key of the sendgrid account
  • -
  • Email addresses: recipients of the emails
  • -
-

File

-
    -
  • File path: path where the logs will be write
  • -
  • Max file size: when size is reached, Otoroshi will create a new file postfixed by the current timestamp
  • -
-

GoReplay file

-

With this kind of exporter, every matching event will be sent to a .gor file compatible with GoReplay.

Warning
-

this exporter will only be able to catch TrafficCaptureEvent. Those events are created when a route (or the global config) of the new proxy engine is setup to capture traffic using the capture flag.

-
    -
  • File path: path where the logs will be write
  • -
  • Max file size: when size is reached, Otoroshi will create a new file postfixed by the current timestamp
  • -
  • Capture requests: capture http requests in the .gor file
  • -
  • Capture responses: capture http responses in the .gor file
  • -
-

Console

-

Nothing to add. The events will be write on the standard output.

-

Custom

-

This type of exporter let you the possibility to write your own exporter with your own rules. To create an exporter, we need to navigate to the plugins page, and to create a new item of type exporter.

-

When it’s done, the exporter will be visible in this list.

-
    -
  • Exporter config.: the configuration of the custom exporter.
  • -
-

Metrics

-

This plugin is useful to rewrite the metric labels exposed on the /metrics endpoint.

-
    -
  • Labels: list of metric labels. Each pair contains an existing field name and the new name.
  • -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/global-config.html b/docs/manual/entities/global-config.html deleted file mode 100644 index 454bf62493..0000000000 --- a/docs/manual/entities/global-config.html +++ /dev/null @@ -1,527 +0,0 @@ - - - - -Global config · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Global config

-

The global config, named Danger zone in Otoroshi, is the place to configure Otoroshi globally.

-
-

Warning: In this page, the configuration is really sensitive and affect the global behaviour of Otoroshi.

-
-

Misc. Settings

-
    -
  • Maintenance mode : It pass every single service in maintenance mode. If an user calls a service, the maintenance page will be displayed
  • -
  • No OAuth login for BackOffice : Forces admins to login only with user/password or user/password/u2F device
  • -
  • API Read Only: Freeze the Otoroshi datastore in read only mode. Only people with access to the actual underlying datastore will be able to disable this.
  • -
  • Auto link default : When no group is specified on a service, it will be assigned to default one
  • -
  • Use circuit breakers : Use circuit breaker on all services
  • -
  • Use new http client as the default Http client : All http calls will use the new http client by default
  • -
  • Enable live metrics : Enable live metrics in the Otoroshi cluster. Performs a lot of writes in the datastore
  • -
  • Digitus medius : Use middle finger emoji as a response character for endless HTTP responses.
  • -
  • Limit conc. req. : Limit the number of concurrent request processed by Otoroshi to a certain amount. Highly recommended for resilience
  • -
  • Use X-Forwarded-* headers for routing : When evaluating routing of a request, X-Forwarded-* headers will be used if presents
  • -
  • Max conc. req. : Maximum number of concurrent requests processed by otoroshi.
  • -
  • Max HTTP/1.0 resp. size : Maximum size of an HTTP/1.0 response in bytes. After this limit, response will be cut and sent as is. The best value here should satisfy (maxConcurrentRequests * maxHttp10ResponseSize) < process.memory for worst case scenario.
  • -
  • Max local events : Maximum number of events stored.
  • -
  • Lines : deprecated
  • -
-

IP address filtering settings

-
    -
  • IP allowed list: Only IP addresses that will be able to access Otoroshi exposed services
  • -
  • IP blocklist: IP addresses that will be refused to access Otoroshi exposed services
  • -
  • Endless HTTP Responses: IP addresses for which each request will return around 128 Gb of 0s
  • -
-

Quotas settings

-
    -
  • Global throttling: The max. number of requests allowed per second globally on Otoroshi
  • -
  • Throttling per IP: The max. number of requests allowed per second per IP address globally on Otoroshi
  • -
-

Analytics: Elastic dashboard datasource (read)

-
    -
  • Cluster URI: Elastic cluster URI
  • -
  • Index: Elastic index
  • -
  • Type: Event type (not needed for elasticsearch above 6.x)
  • -
  • User: Elastic User (optional)
  • -
  • Password: Elastic password (optional)
  • -
  • Version: Elastic version (optional, if none provided it will be fetched from cluster)
  • -
  • Apply template: Automatically apply index template
  • -
  • Check Connection: Button to test the configuration. It will displayed a modal with checked point, and if the case of it’s successfull, it will displayed the found version of the Elasticsearch and the index used
  • -
  • Manually apply index template: try to put the elasticsearch template by calling the api of elasticsearch
  • -
  • Show index template: try to retrieve the current index template presents in elasticsearch
  • -
  • Client side temporal indexes handling: When enabled, Otoroshi will manage the creation of indexes. When it’s disabled, Otoroshi will push in the same index
  • -
  • One index per: When the previous field is enabled, you can choose the interval of time between the creation of a new index in elasticsearch
  • -
  • Custom TLS Settings: Enable the TLS configuration for the communication with Elasticsearch
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • TrustAll: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with elasticsearch
  • -
  • Trusted certificates: list of trusted certificates received from elasticsearch
  • -
-

Statsd settings

-
    -
  • Datadog agent: The StatsD agent is a Datadog agent
  • -
  • StatsD agent host: The host on which StatsD agent is listening
  • -
  • StatsD agent port: The port on which StatsD agent is listening (default is 8125)
  • -
-

Backoffice auth. settings

-
    -
  • Backoffice auth. config: the authentication module used in front of Otoroshi. It will be used to connect to Otoroshi on the login page
  • -
-

Let’s encrypt settings

-
    -
  • Enabled: when enabled, Otoroshi will have the possiblity to sign certificate from let’s encrypt notably in the SSL/TSL Certificates page
  • -
  • Server URL: ACME endpoint of let’s encrypt
  • -
  • Email addresses: (optional) list of addresses used to order the certificates
  • -
  • Contact URLs: (optional) list of addresses used to order the certificates
  • -
  • Public Key: used to ask a certificate to let’s encrypt, generated by Otoroshi
  • -
  • Private Key: used to ask a certificate to let’s encrypt, generated by Otoroshi
  • -
-

CleverCloud settings

-

Once configured, you can register one clever cloud app of your organization directly as an Otoroshi service.

-
    -
  • CleverCloud consumer key: consumer key of your clever cloud OAuth 1.0 app
  • -
  • CleverCloud consumer secret: consumer secret of your clever cloud OAuth 1.0 app
  • -
  • OAuth Token: oauth token of your clever cloud OAuth 1.0 app
  • -
  • OAuth Secret: oauth token secret of your clever cloud OAuth 1.0 app
  • -
  • CleverCloud orga. Id: id of your clever cloud organization
  • -
-

Global scripts

-

Global scripts will be deprecated soon, please use global plugins instead (see the next section)!

-

Global plugins

-
    -
  • Enabled: enabled all global plugins
  • -
  • Plugins: list of added plugins to your instance
  • -
  • Plugin configuration: each added plugin have a configuration that you can override from this field
  • -
-

Proxies

-

In this section, you can add a list of proxies for :

-
    -
  • Proxy for alert emails (mailgun)
  • -
  • Proxy for alert webhooks
  • -
  • Proxy for Clever-Cloud API access
  • -
  • Proxy for services access
  • -
  • Proxy for auth. access (OAuth, OIDC)
  • -
  • Proxy for client validators
  • -
  • Proxy for JWKS access
  • -
  • Proxy for elastic access
  • -
-

Each proxy has the following fields

-
    -
  • Proxy host: host of proxy
  • -
  • Proxy port: port of proxy
  • -
  • Proxy principal: user of proxy
  • -
  • Proxy password: password of proxy
  • -
  • Non proxy host: IP address that can access the service
  • -
-

Quotas alerting settings

-
    -
  • Enable quotas exceeding alerts: When apikey quotas is almost exceeded, an alert will be sent
  • -
  • Daily quotas threshold: The percentage of daily calls before sending alerts
  • -
  • Monthly quotas threshold: The percentage of monthly calls before sending alerts
  • -
-

User-Agent extraction settings

-
    -
  • User-Agent extraction: Allow user-agent details extraction. Can have impact on consumed memory. 
  • -
-

Geolocation extraction settings

-

Extract an geolocation for each call to Otoroshi.

-

Tls Settings

-
    -
  • Use random cert.: Use the first available cert none matches the current domain
  • -
  • Default domain: When the SNI domain cannot be found, this one will be used to find the matching certificate 
  • -
  • Trust JDK CAs (server): Trust JDK CAs. The CAs from the JDK CA bundle will be proposed in the certificate request when performing TLS handshake 
  • -
  • Trust JDK CAs (trust): Trust JDK CAs. The CAs from the JDK CA bundle will be used as trusted CAs when calling HTTPS resources 
  • -
  • Trusted CAs (server): Select the trusted CAs you want for TLS terminaison. Those CAs only will be proposed in the certificate request when performing TLS handshake 
  • -
-

Auto Generate Certificates

-
    -
  • Enabled: Generate certificates on the fly when they not exist
  • -
  • Reply Nicely: When not allowed domain name, accept connection and display a nice error message 
  • -
  • CA: certificate CA used to generate missing certificate
  • -
  • Allowed domains: Allowed domains
  • -
  • Not allowed domains: Allowed domains
  • -
-

Global metadata

-
    -
  • Tags: tags attached to the global config
  • -
  • Metadata: metadata attached to the global config
  • -
-

Actions at the bottom of the page

-
    -
  • Recover from a full export file: Load global configuration from a previous export
  • -
  • Full export: Export with all created entities
  • -
  • Full export (ndjson): Export your full state of database to ndjson format
  • -
  • JSON: Get the global config at JSON format 
  • -
  • YAML: Get the global config at YAML format 
  • -
  • Enable Panic Mode: Log out all users from UI and prevent any changes to the database by setting the admin Otoroshi api to read-only. The only way to exit of this mode is to disable this mode directly in the database. 
  • -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/index.html b/docs/manual/entities/index.html deleted file mode 100644 index 84a8a429fb..0000000000 --- a/docs/manual/entities/index.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - -Main entities · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Main entities

-

In this section, we will pass through all the main Otoroshi entities. Otoroshi entities are the main items stored in otoroshi datastore that will be used to configure routing, authentication, etc.

-

Any entity has the following properties

-
    -
  • location or _loc: the location of the entity (organization and team)
  • -
  • id: the id of the entity (except for apikeys)
  • -
  • name: the name of the entity
  • -
  • description: the description of the entity (optional)
  • -
  • tags: free tags that you can put on any entity to help you manage it, automate it, etc.
  • -
  • metadata: free key/value tuples that you can put on any entity to help you manage it, automate it, etc.
  • -
- -
-Organizations -This the most high level for grouping resources. -
-

View

- -
-Teams -Organize your resources by teams -
-

View

- -
-Service groups -Group your services -
-

View

- -
-JWT verifiers -Verify and forge token by services. -
-

View

- -
-Apikeys -Add security to your services using apikeys -
-

View

- -
-Global Config -The danger zone of Otoroshi -
-

View

- -
-Service descriptors -Proxy your applications with service descriptors -
-

View

- -
-TCP services - -
-

View

- -
-Auth. modules -Secure the Otoroshi UI and your web apps -
-

View

- -
-Certificates -Add secure communication between Otoroshi, clients and services -
-

View

- -
-Data exporters -Export alerts, events ands logs -
-

View

- -
-Scripts - -
-

View

- -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/jwt-verifiers.html b/docs/manual/entities/jwt-verifiers.html deleted file mode 100644 index ae27b7327f..0000000000 --- a/docs/manual/entities/jwt-verifiers.html +++ /dev/null @@ -1,484 +0,0 @@ - - - - -JWT verifiers · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

JWT verifiers

-

Sometimes, it can be pretty useful to verify Jwt tokens coming from other provider on some services. Otoroshi provides a tool to do that per service.

-
    -
  • Name: name of the JWT verifier
  • -
  • Description: a simple description
  • -
  • Strict: if not strict, request without JWT token will be allowed to pass. This option is helpful when you want to force the presence of tokens in each request on a specific service
  • -
  • Tags: list of tags associated to the module
  • -
  • Metadata: list of metadata associated to the module
  • -
-

Each JWT verifier is configurable in three steps : the location where find the token in incoming requests, the validation step to check the signature and the presence of claims in tokens, and the last step, named Strategy.

-

Token location

-

An incoming token can be found in three places.

-

In query string

-
    -
  • Source: JWT token location in query string
  • -
  • Query param name: the name of the query param where JWT is located
  • -
-

In a header

-
    -
  • Source: JWT token location in a header
  • -
  • Header name: the name of the header where JWT is located
  • -
  • Remove value: when the token is read, this value will be remove of header value (example: if the header value is Bearer xxxx, the remove value could be Bearer  don’t forget the space at the end of the string)
  • -
-

In a cookie

-
    -
  • Source: JWT token location in a cookie
  • -
  • Cookie name: the name of the cookie where JWT is located
  • -
-

Token validation

-

This section is used to verify the extracted token from specified location.

-
    -
  • Algo.: What kind of algorithm you want to use to verify/sign your JWT token with
  • -
-

According to the selected algorithm, the validation form will change.

-

Hmac + SHA

-
    -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • Hmac secret: used to verify the token
  • -
  • Base64 encoded secret: if enabled, the extracted token will be base64 decoded before it is verifier
  • -
-

RSASSA-PKCS1 + SHA

-
    -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • Public key: the RSA public key
  • -
  • Private key: the RSA private key that can be empty if not used for JWT token signing
  • -
-

ECDSA + SHA

-
    -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • Public key: the ECDSA public key
  • -
  • Private key: the ECDSA private key that can be empty if not used for JWT token signing
  • -
-

RSASSA-PKCS1 + SHA from KeyPair

-
    -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • KeyPair: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page
  • -
-

ECDSA + SHA from KeyPair

-
    -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • KeyPair: used to sign/verify token. The displayed list represents the key pair registered in the Certificates page
  • -
-

Otoroshi KeyPair from token kid (only for verification)

-
    -
  • Use only exposed keypairs: if enabled, Otoroshi will only use the key pairs that are exposed on the well-known. If disabled, it will search on any registered key pairs.
  • -
-

JWK Set (only for verification)

-
    -
  • URL: the JWK set URL where the public keys are exposed
  • -
  • HTTP call timeout: timeout for fetching the keyset
  • -
  • TTL: cache TTL for the keyset
  • -
  • HTTP Headers: the HTTP headers passed
  • -
  • Key type: type of the key searched in the jwks
  • -
-

TLS settings for JWKS fetching

-
    -
  • Custom TLS Settings: TLS settings for JWKS fetching
  • -
  • TLS loose: if enabled, will block all untrustful ssl configs
  • -
  • Trust all: allows any server certificates even the self-signed ones
  • -
  • Client certificates: list of client certificates used to communicate with JWKS server
  • -
  • Trusted certificates: list of trusted certificates received from JWKS server
  • -
-

Proxy

-
    -
  • Proxy host: host of proxy behind the identify provider
  • -
  • Proxy port: port of proxy behind the identify provider
  • -
  • Proxy principal: user of proxy
  • -
  • Proxy password: password of proxy
  • -
-

Strategy

-

The first step is to select the verifier strategy. Otoroshi supports 4 types of JWT verifiers:

-
    -
  • Default JWT token will add a token if no present.
  • -
  • Verify JWT token will only verifiy token signing and fields values if provided.
  • -
  • Verify and re-sign JWT token will verify the token and will re-sign the JWT token with the provided algo. settings.
  • -
  • Verify, re-sign and transform JWT token will verify the token, re-sign and will be able to transform the token.
  • -
-

All verifiers has the following properties:

-
    -
  • Verify token fields: when the JWT token is checked, each field specified here will be verified with the provided value
  • -
  • Verify token array value: when the JWT token is checked, each field specified here will be verified if the provided value is contained in the array
  • -
-

Default JWT token

-
    -
  • Strict: if token is already present, the call will fail
  • -
  • Default value: list of claims of the generated token. These fields support raw values or language expressions. See the documentation about the expression language
  • -
-

Verify JWT token

-

No specific values needed. This kind of verifier needs only the two fields Verify token fields and Verify token array value.

-

Verify and re-sign JWT token

-

When Verify and re-sign JWT token is chosen, the Re-sign settings appear. All fields of Re-sign settings are the same of the Token validation section. The only difference is that the values are used to sign the new token and not to validate the token.

-

Verify, re-sign and transform JWT token

-

When Verify, re-sign and transform JWT token is chosen, the Re-sign settings and Transformation settings appear.

-

The Re-sign settings are used to sign the new token and has the same fields than the Token validation section.

-

For the Transformation settings section, the fields are:

-
    -
  • Token location: the location where to find/set the JWT token
  • -
  • Header name: the name of the header where JWT is located
  • -
  • Prepend value: remove a value inside the header value
  • -
  • Rename token fields: when the JWT token is transformed, it is possible to change a field name, just specify origin field name and target field name
  • -
  • Set token fields: when the JWT token is transformed, it is possible to add new field with static values, just specify field name and value
  • -
  • Remove token fields: when the JWT token is transformed, it is possible to remove fields
  • -
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/organizations.html b/docs/manual/entities/organizations.html deleted file mode 100644 index bd31b8cbfd..0000000000 --- a/docs/manual/entities/organizations.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - -Organizations · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Organizations

-

The resources of Otoroshi are grouped by Organization. This the highest level for grouping resources.

-

An organization have a unique id, a name and a description. As all Otoroshi resources, an Organization have a list of tags and metadata associated.

-

For example, you can use the organizations as a mean of :

-
    -
  • to seperate resources by services or entities in your enterprise
  • -
  • to split internal and external usage of the resources (it’s useful when you have a list of services deployed in your company and another one deployed by your partners)
  • -
-
-

Access to the list of organizations

-

To visualize and edit the list of organizations, you can navigate to your instance on the https://otoroshi.xxxxxx/bo/dashboard/organizations route or click on the cog icon and select the organizations button.

-

Once on the page, you can create a new item, edit an existing organization or delete an existing one.

-
-

When an organization is deleted, the resources associated are not deleted. On the other hand, the organization and the team of associated resources are let empty.

-
-

Entities location

-

Any otoroshi entity has a location property (_loc when serialized to json) explaining where and by whom the entity can be seen.

-

An entity can be part of one organization (tenant in the json document)

-
{
-  "_loc": {
-    "tenant": "tenant-1",
-    "teams": ...
-  }
-  ...
-}
-
-

or all organizations

-
{
-  "_loc": {
-    "tenant": "*",
-    "teams": ...
-  }
-  ...
-}
-
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/scripts.html b/docs/manual/entities/scripts.html deleted file mode 100644 index c7f9918200..0000000000 --- a/docs/manual/entities/scripts.html +++ /dev/null @@ -1,377 +0,0 @@ - - - - -Scripts · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Scripts

-

Script are a way to create plugins for otoroshi without deploying them as jar files. With scripts, you just have to store the scala code of your plugins inside the otoroshi datastore and otoroshi will compile and deploy them at startup. You can find all your scripts in the UI at cog icon / Plugins. You can find all the documentation about plugins here

Warning
-

The compilation of your plugins can be pretty long and resources consuming. As the compilation happens during otoroshi boot sequence, your instance will be blocked until all plugins have compiled. This behavior can be disabled. If so, the plugins will not work until they have been compiled. Any service using a plugin that is not compiled yet will fail

-

Like any entity, the script has has the following properties

-
    -
  • id
  • -
  • plugin name
  • -
  • plugin description
  • -
  • tags
  • -
  • metadata
  • -
-

And you also have

-
    -
  • type: the kind of plugin you are building with this script
  • -
  • plugin code: the code for your plugin
  • -
-

Compile

-

You can use the compile button to check if the code you write in plugin code is valid. It will automatically save your script and try to compile. As mentionned earlier, script compilation is quite resource intensive. It will affect your CPU load and your memory consumption. Don’t forget to adjust your VM settings accordingly.

- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/service-descriptors.html b/docs/manual/entities/service-descriptors.html deleted file mode 100644 index 8f859dbcd3..0000000000 --- a/docs/manual/entities/service-descriptors.html +++ /dev/null @@ -1,656 +0,0 @@ - - - - -Service descriptors · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Service descriptors

-

Services or service descriptor, let you declare how to proxy a call from a domain name to another domain name (or multiple domain names).

-
-

Let’s say you have an API exposed on http://192.168.0.42 and I want to expose it on https://my.api.foo. Otoroshi will proxy all calls to https://my.api.foo and forward them to http://192.168.0.42. While doing that, it will also log everyhting, control accesses, etc.

-
    -
  • Id: a unique random string to identify your service
  • -
  • Groups: each service descriptor is attached to a group. A group can have one or more services. Each API key is linked to a group and allow access to every service in the group.
  • -
  • Create a new group: you can create a new group to host this descriptor
  • -
  • Create dedicated group: you can create a new group with an auto generated name to host this descriptor
  • -
  • Name: the name of your service. Only for debug and human readability purposes.
  • -
  • Description: the description of your service. Only for debug and human readability purposes.
  • -
  • Service enabled: activate or deactivate your service. Once disabled, users will get an error page saying the service does not exist.
  • -
  • Read only mode: authorize only GET, HEAD, OPTIONS calls on this service
  • -
  • Maintenance mode: display a maintainance page when a user try to use the service
  • -
  • Construction mode: display a construction page when a user try to use the service
  • -
  • Log analytics: Log analytics events for this service on the servers
  • -
  • Use new http client: will use Akka Http Client for every request
  • -
  • Detect apikey asap: If the service is public and you provide an apikey, otoroshi will detect it and validate it. Of course this setting may impact performances because of useless apikey lookups.
  • -
  • Send Otoroshi headers back: when enabled, Otoroshi will send headers to consumer like request id, client latency, overhead, etc …
  • -
  • Override Host header: when enabled, Otoroshi will automatically set the Host header to corresponding target host
  • -
  • Send X-Forwarded-* headers: when enabled, Otoroshi will send X-Forwarded-* headers to target
  • -
  • Force HTTPS: will force redirection to https:// if not present
  • -
  • Allow HTTP/1.0 requests: will return an error on HTTP/1.0 request
  • -
  • Use new WebSocket client: will use the new websocket client for every websocket request
  • -
  • TCP/UDP tunneling: with this setting enabled, otoroshi will not proxy http requests anymore but instead will create a secured tunnel between a cli on your machine and otoroshi to proxy any tcp connection with all otoroshi security features enabled
  • -
-

Service exposition settings

-
    -
  • Exposed domain: the domain used to expose your service. Should follow pattern: (http|https)://subdomain?.env?.domain.tld?/root? or regex (http|https):\/\/(.*?)\.?(.*?)\.?(.*?)\.?(.*)\/?(.*)
  • -
  • Legacy domain: use domain, subdomain, env and matchingRoot for routing in addition to hosts, or just use hosts.
  • -
  • Strip path: when matching, strip the matching prefix from the upstream request URL. Defaults to true
  • -
  • Issue Let's Encrypt cert.: automatically issue and renew let’s encrypt certificate based on domain name. Only if Let’s Encrypt enabled in global config.
  • -
  • Issue certificate: automatically issue and renew a certificate based on domain name
  • -
  • Possible hostnames: all the possible hostnames for your service
  • -
  • Possible matching paths: all the possible matching paths for your service
  • -
-

Redirection

-
    -
  • Redirection enabled: enabled the redirection. If enabled, a call to that service will redirect to the chosen URL
  • -
  • Http redirection code: type of redirection used
  • -
  • Redirect to: URL used to redirect user when the service is called
  • -
-

Service targets

-
    -
  • Redirect to local: if you work locally with Otoroshi, you may want to use that feature to redirect one specific service to a local host. For example, you can relocate https://foo.preprod.bar.com to http://localhost:8080 to make some tests
  • -
  • Load balancing: the load balancing algorithm used
  • -
  • Targets: the list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures
  • -
  • Targets root: Otoroshi will append this root to any target choosen. If the specified root is /api/foo, then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar
  • -
-

URL Patterns

-
    -
  • Make service a 'public ui': add a default pattern as public routes
  • -
  • Make service a 'private api': add a default pattern as private routes
  • -
  • Public patterns: by default, every services are private only and you’ll need an API key to access it. However, if you want to expose a public UI, you can define one or more public patterns (regex) to allow access to anybody. For example if you want to allow anybody on any URL, just use /.*
  • -
  • Private patterns: if you define a public pattern that is a little bit too much, you can make some of public URL private again
  • -
-

Restrictions

-
    -
  • Enabled: enable restrictions
  • -
  • Allow last: Otoroshi will test forbidden and notFound paths before testing allowed paths
  • -
  • Allowed: allowed paths
  • -
  • Forbidden: forbidden paths
  • -
  • Not Found: not found paths
  • -
-

Otoroshi exchange protocol

-
    -
  • Enabled: when enabled, Otoroshi will try to exchange headers with backend service to ensure no one else can use the service from outside.
  • -
  • Send challenge: when disbaled, Otoroshi will not check if target service respond with sent random value.
  • -
  • Send info. token: when enabled, Otoroshi add an additional header containing current call informations
  • -
  • Challenge token version: version the otoroshi exchange protocol challenge. This option will be set to V2 in a near future.
  • -
  • Info. token version: version the otoroshi exchange protocol info token. This option will be set to Latest in a near future.
  • -
  • Tokens TTL: the number of seconds for tokens (state and info) lifes
  • -
  • State token header name: the name of the header containing the state token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.state)
  • -
  • State token response header name: the name of the header containing the state response token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.stateresp)
  • -
  • Info token header name: the name of the header containing the info token. If not specified, the value will be taken from the configuration (otoroshi.headers.comm.claim)
  • -
  • Excluded patterns: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.
  • -
  • Use same algo.: when enabled, all JWT token in this section will use the same signing algorithm. If use same algo. is disabled, three more options will be displayed to select an algorithm for each step of the calls : -
      -
    • Otoroshi to backend
    • -
    • Backend to otoroshi
    • -
    • Info. token
    • -
    -
  • -
  • -

    Algo.: What kind of algorithm you want to use to verify/sign your JWT token with

  • -
  • SHA Size: Word size for the SHA-2 hash function used
  • -
  • Hmac secret: used to verify the token
  • -
  • Base64 encoded secret: if enabled, the extracted token will be base64 decoded before it is verifier
  • -
-

Authentication

-
    -
  • Enforce user authentication: when enabled, user will be allowed to use the service (UI) only if they are registered users of the chosen authentication module.
  • -
  • Auth. config: authentication module used to protect the service
  • -
  • Create a new auth config.: navigate to the creation of authentication module page
  • -
  • all auth config.: navigate to the authentication pages
  • -
  • -

    Excluded patterns: by default, when security is enabled, everything is secured. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.

  • -
  • Strict mode: strict mode enabled
  • -
-

Api keys constraints

-
    -
  • From basic auth.: you can pass the api key in Authorization header (ie. from ‘Authorization: Basic xxx’ header)
  • -
  • Allow client id only usage: you can pass the api key using client id only (ie. from Otoroshi-Token header)
  • -
  • From custom headers: you can pass the api key using custom headers (ie. Otoroshi-Client-Id and Otoroshi-Client-Secret headers)
  • -
  • From JWT token: you can pass the api key using a JWT token (ie. from ‘Authorization: Bearer xxx’ header)
  • -
-

Basic auth. Api Key

-
    -
  • Custom header name: the name of the header to get Authorization
  • -
  • Custom query param name: the name of the query param to get Authorization
  • -
-

Client ID only Api Key

-
    -
  • Custom header name: the name of the header to get the client id
  • -
  • Custom query param name: the name of the query param to get the client id
  • -
-

Custom headers Api Key

-
    -
  • Custom client id header name: the name of the header to get the client id
  • -
  • Custom client secret header name: the name of the header to get the client secret
  • -
-

JWT Token Api Key

-
    -
  • Secret signed: JWT can be signed by apikey secret using HMAC algo.
  • -
  • Keypair signed: JWT can be signed by an otoroshi managed keypair using RSA/EC algo.
  • -
  • Include Http request attrs.: if enabled, you have to put the following fields in the JWT token corresponding to the current http call (httpPath, httpVerb, httpHost)
  • -
  • Max accepted token lifetime: the maximum number of second accepted as token lifespan
  • -
  • Custom header name: the name of the header to get the jwt token
  • -
  • Custom query param name: the name of the query param to get the jwt token
  • -
  • Custom cookie name: the name of the cookie to get the jwt token
  • -
-

Routing constraints

-
    -
  • All Tags in : have all of the following tags
  • -
  • No Tags in : not have one of the following tags
  • -
  • One Tag in : have at least one of the following tags
  • -
  • All Meta. in : have all of the following metadata entries
  • -
  • No Meta. in : not have one of the following metadata entries
  • -
  • One Meta. in : have at least one of the following metadata entries
  • -
  • One Meta key in : have at least one of the following key in metadata
  • -
  • All Meta key in : have all of the following keys in metadata
  • -
  • No Meta key in : not have one of the following keys in metadata
  • -
-

CORS support

-
    -
  • Enabled: if enabled, CORS header will be check for each incoming request
  • -
  • Allow credentials: if enabled, the credentials will be sent. Credentials are cookies, authorization headers, or TLS client certificates.
  • -
  • Allow origin: if enabled, it will indicates whether the response can be shared with requesting code from the given
  • -
  • Max age: response header indicates how long the results of a preflight request (that is the information contained in the Access-Control-Allow-Methods and Access-Control-Allow-Headers headers) can be cached.
  • -
  • Expose headers: response header allows a server to indicate which response headers should be made available to scripts running in the browser, in response to a cross-origin request.
  • -
  • Allow headers: response header is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request.
  • -
  • Allow methods: response header specifies one or more methods allowed when accessing a resource in response to a preflight request.
  • -
  • Excluded patterns: by default, when cors is enabled, everything has cors. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.
  • -
-

Related documentations

- -

JWT tokens verification

-
    -
  • Verifiers: list of selected verifiers to apply on the service
  • -
  • Enabled: if enabled, Otoroshi will enabled each verifier of the previous list
  • -
  • Excluded patterns: list of routes where the verifiers will not be apply
  • -
-

Pre Routing

-

This part has been deprecated and moved to the plugin section.

-

Access validation

-

This part has been deprecated and moved to the plugin section.

-

Gzip support

-
    -
  • Mimetypes allowed list: gzip only the files that are matching to a format in the list
  • -
  • Mimetypes blocklist: will not gzip files matching to a format in the list. A possible way is to allowed all format by default by setting a * on the Mimetypes allowed list and to add the unwanted format in this list.
  • -
  • Compression level: the compression level where 9 gives us maximum compression but at the slowest speed. The default compression level is 5 and is a good compromise between speed and compression ratio.
  • -
  • Buffer size: chunking up a stream of bytes into limited size
  • -
  • Chunk threshold: if the content type of a request reached over the threshold, the response will be chunked
  • -
  • Excluded patterns: by default, when gzip is enabled, everything has gzip. But sometimes you need to exlude something, so just add regex to matching path you want to exlude.
  • -
-

Client settings

-
    -
  • Use circuit breaker: use a circuit breaker to avoid cascading failure when calling chains of services. Highly recommended !
  • -
  • Cache connections: use a cache at host connection level to avoid reconnection time
  • -
  • Client attempts: specify how many times the client will retry to fetch the result of the request after an error before giving up.
  • -
  • Client call timeout: specify how long each call should last at most in milliseconds.
  • -
  • Client call and stream timeout: specify how long each call should last at most in milliseconds for handling the request and streaming the response.
  • -
  • Client connection timeout: specify how long each connection should last at most in milliseconds.
  • -
  • Client idle timeout: specify how long each connection can stay in idle state at most in milliseconds.
  • -
  • Client global timeout: specify how long the global call (with retries) should last at most in milliseconds.
  • -
  • C.breaker max errors: specify how many errors can pass before opening the circuit breaker
  • -
  • C.breaker retry delay: specify the delay between two retries. Each retry, the delay is multiplied by the backoff factor
  • -
  • C.breaker backoff factor: specify the factor to multiply the delay for each retry
  • -
  • C.breaker window: specify the sliding window time for the circuit breaker in milliseconds, after this time, error count will be reseted
  • -
-

Custom timeout settings (list)

-
    -
  • Path: the path on which the timeout will be active
  • -
  • Client connection timeout: specify how long each connection should last at most in milliseconds.
  • -
  • Client idle timeout: specify how long each connection can stay in idle state at most in milliseconds.
  • -
  • Client call and stream timeout: specify how long each call should last at most in milliseconds for handling the request and streaming the response.
  • -
  • Call timeout: Specify how long each call should last at most in milliseconds.
  • -
  • Client global timeout: specify how long the global call (with retries) should last at most in milliseconds.
  • -
-

Proxy settings

-
    -
  • Proxy host: host of proxy behind the identify provider
  • -
  • Proxy port: port of proxy behind the identify provider
  • -
  • Proxy principal: user of proxy
  • -
  • Proxy password: password of proxy
  • -
-

HTTP Headers

-
    -
  • Additional Headers In: specify headers that will be added to each client request (from Otoroshi to target). Useful to add authentication.
  • -
  • Additional Headers Out: specify headers that will be added to each client response (from Otoroshi to client).
  • -
  • Missing only Headers In: specify headers that will be added to each client request (from Otoroshi to target) if not in the original request.
  • -
  • Missing only Headers Out: specify headers that will be added to each client response (from Otoroshi to client) if not in the original response.
  • -
  • Remove incoming headers: remove headers in the client request (from client to Otoroshi).
  • -
  • Remove outgoing headers: remove headers in the client response (from Otoroshi to client).
  • -
  • Security headers:
  • -
  • Utility headers:
  • -
  • Matching Headers: specify headers that MUST be present on client request to route it (pre routing). Useful to implement versioning.
  • -
  • Headers verification: verify that some headers has a specific value (post routing)
  • -
-

Additional settings

-
    -
  • OpenAPI: specify an open API descriptor. Useful to display the documentation
  • -
  • Tags: specify tags for the service
  • -
  • Metadata: specify metadata for the service. Useful for analytics
  • -
  • IP allowed list: IP address that can access the service
  • -
  • IP blocklist: IP address that cannot access the service
  • -
-

Canary mode

-
    -
  • Enabled: Canary mode enabled
  • -
  • Traffic split: Ratio of traffic that will be sent to canary targets. For instance, if traffic is at 0.2, for 10 request, 2 request will go on canary targets and 8 will go on regular targets.
  • -
  • Targets: The list of target that Otoroshi will proxy and expose through the subdomain defined before. Otoroshi will do round-robin load balancing between all those targets with circuit breaker mecanism to avoid cascading failures
  • -
  • Target:
  • -
  • Targets root: Otoroshi will append this root to any target choosen. If the specified root is ‘/api/foo’, then a request to https://yyyyyyy/bar will actually hit https://xxxxxxxxx/api/foo/bar
  • -
  • Campaign stats:
  • -
  • Use canary targets as standard targets:
  • -
-

Healthcheck settings

-
    -
  • HealthCheck enabled: to help failing fast, you can activate healthcheck on a specific URL.
  • -
  • HealthCheck url: the URL to check. Should return an HTTP 200 response. You can also respond with an ‘Opun-Health-Check-Logic-Test-Result’ header set to the value of the ‘Opun-Health-Check-Logic-Test’ request header + 42. to make the healthcheck complete.
  • -
-

Fault injection

-
    -
  • User facing app.: if service is set as user facing, Snow Monkey can be configured to not being allowed to create outage on them.
  • -
  • Chaos enabled: activate or deactivate chaos setting on this service descriptor.
  • -
-

Custom errors template

-
    -
  • 40x template: html template displayed when 40x error occurred
  • -
  • 50x template: html template displayed when 50x error occurred
  • -
  • Build mode template: html template displayed when the build mode is enabled
  • -
  • Maintenance mode template: html template displayed when the maintenance mode is enabled
  • -
  • Custom messages: override error message one by one
  • -
-

Request transformation

-

This part has been deprecated and moved to the plugin section.

-

Plugins

-
    -
  • Plugins: -
      -
    • Inject default config: injects, if present, the default configuration of a selected plugin in the configuration object
    • -
    • Documentation: link to the documentation website of the plugin
    • -
    • show/hide config. panel: shows and hides the plugin panel which contains the plugin description and configuration
    • -
    -
  • -
  • Excluded patterns: by default, when plugins are enabled, everything pass in. But sometimes you need to exclude something, so just add regex to matching path you want to exlude.
  • -
  • Configuration: the configuration of each enabled plugin, split by names and grouped in the same configuration object.
  • -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/service-groups.html b/docs/manual/entities/service-groups.html deleted file mode 100644 index b4ca33cd91..0000000000 --- a/docs/manual/entities/service-groups.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - -Service groups · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Service groups

-

A service group is composed of an unique id, a Group name, a Group description, an Organization and a Team. As all Otoroshi resources, a service group have a list of tags and metadata associated.

-
-

The first instinctive usage of service group is to group a list of services.

-

When it’s done, you can authorize an api key on a specific group. Instead of authorize an api key for each service, you can regroup a list of services together, and give authorization on the group (read the page on the api keys and the usage of the Authorized on. field).

-

Access to the list of service groups

-

To visualize and edit the list of groups, you can navigate to your instance on the https://otoroshi.xxxxx/bo/dashboard/groups route or click on the cog icon and select the Service groups button.

-

Once on the page, you can create a new item, edit an existing service group or delete an existing one.

-
-

When a service group is deleted, the resources associated are not deleted. On the other hand, the service group of associated resources is let empty.

-
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/tcp-services.html b/docs/manual/entities/tcp-services.html deleted file mode 100644 index ce8a7347e3..0000000000 --- a/docs/manual/entities/tcp-services.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - -TCP services · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

TCP services

-

TCP service are special kind of otoroshi services meant to proxy pure TCP connections (ssh, database, http, etc)

-

Global information

-
    -
  • Id: generated unique identifier
  • -
  • TCP service name: the name of your TCP service
  • -
  • Enabled: enable and disable the service
  • -
  • TCP service port: the listening port
  • -
  • TCP service interface: network interface listen by the service
  • -
  • Tags: list of tags associated to the service
  • -
  • Metadata: list of metadata associated to the service
  • -
-

TLS

-

this section controls the TLS exposition of the service

-
    -
  • TLS mode -
      -
    • Disabled: no TLS
    • -
    • PassThrough: as the target exposes TLS, the call will pass through otoroshi and use target TLS
    • -
    • Enabled: the service will be exposed using TLS and will chose certificate based on SNI
    • -
    -
  • -
  • Client Auth. -
      -
    • None no mTLS needed to pass
    • -
    • Want pass with or without mTLS
    • -
    • Need need mTLS to pass
    • -
    -
  • -
-

Server Name Indication (SNI)

-

this section control how SNI should be treated

-
    -
  • SNI routing enabled: if enabled, the server will use the SNI hostname to determine which certificate to present to the client
  • -
  • Forward to target if no SNI match: if enabled, a call without any SNI match will be forward to the target
  • -
  • Target host: host of the target called if no SNI
  • -
  • Target ip address: ip of the target called if no SNI
  • -
  • Target port: port of the target called if no SNI
  • -
  • TLS call: encrypt the communication with TLS
  • -
-

Rules

-

for any listening TCP proxy, it is possible to route to multiple targets based on SNI or extracted http host (if proxying http)

-
    -
  • Matching domain name: regex used to filter the list of domains where the rule will be applied
  • -
  • Target host: host of the target
  • -
  • Target ip address: ip of the target
  • -
  • Target port: port of the target
  • -
  • TLS call: enable this flag if the target is exposed using TLS
  • -
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/entities/teams.html b/docs/manual/entities/teams.html deleted file mode 100644 index 635310cce3..0000000000 --- a/docs/manual/entities/teams.html +++ /dev/null @@ -1,397 +0,0 @@ - - - - -Teams · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Teams

-

In Otoroshi, all resources are attached to an Organization and a Team.

-

A team is composed of an unique id, a name, a description and an Organization. As all Otoroshi resources, a Team have a list of tags and metadata associated.

-

A team have an unique organization and can be use on multiples resources (services, api keys, etc …).

-

A connected user on Otoroshi UI has a list of teams and organizations associated. It can be helpful when you want restrict the rights of a connected user.

-
-

Access to the list of teams

-

To visualize and edit the list of teams, you can navigate to your instance on the https://otoroshi.xxxxxx/bo/dashboard/teams route or click on the cog icon and select the teams button.

-

Once on the page, you can create a new item, edit an existing team or delete an existing one.

-
-

When a team is deleted, the resources associated are not deleted. On the other hand, the team of associated resources is let empty.

-
-

Entities location

-

Any otoroshi entity has a location property (_loc when serialized to json) explaining where and by whom the entity can be seen.

-

An entity can be part of multiple teams in an organization

-
{
-  "_loc": {
-    "tenant": "tenant-1",
-    "teams": [
-      "team-1",
-      "team-2"
-    ]
-  }
-  ...
-}
-
-

or all teams

-
{
-  "_loc": {
-    "tenant": "tenant-1",
-    "teams": [
-      "*"
-    ]
-  }
-  ...
-}
-
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/features.html b/docs/manual/features.html deleted file mode 100644 index c0208d7b0d..0000000000 --- a/docs/manual/features.html +++ /dev/null @@ -1,437 +0,0 @@ - - - - -Features · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Features

-

Traffic Management

-
    -
  • Can proxy any HTTP(s) service (apis, webapps, websocket, etc)
  • -
  • Can proxy any TCP service (app, database, etc)
  • -
  • Traffic mirroring
  • -
  • Canary deployments
  • -
  • Multiple load-balancing options: RoundRobin, Random, Sticky, Ip Hash, Best Response Time
  • -
  • Distributed in-flight request limiting
  • -
  • Distributed rate limiting
  • -
-

Services customization

-
    -
  • Dozens of built-in middlewares (plugins) -
      -
    • circuit breakers
    • -
    • automatic retries
    • -
    • buffering
    • -
    • gzip
    • -
    • headers manipulation
    • -
    • cors
    • -
    • etc
    • -
    -
  • -
  • Custom middleware
  • -
  • Higly customizable visibility
  • -
-

Services Monitoring

-
    -
  • Active health checks
  • -
  • Calls tracing
  • -
  • Export alerts and events to external database
  • -
  • Real-time traffic metrics
  • -
  • Alert mailers
  • -
  • Real-time traffic metrics (Datadog, Prometheus, StatsD)
  • -
-

API security

-
    -
  • Access management with apikeys and quotas
  • -
  • Automatic apikeys secrets rotation
  • -
  • HTTPS and TLS
  • -
  • mTLS in/out calls
  • -
  • Routing constraints
  • -
  • Routing restrictions
  • -
  • JWT tokens validation and manipulation
  • -
-

Administration UI

-
    -
  • Manage and organize all resources
  • -
  • Secured users access with Authentication module
  • -
  • Traced users actions
  • -
  • Dynamic changes at runtime without full reload
  • -
-

Webapp authentication and security

-
    -
  • OAuth2.0/2.1 authentication
  • -
  • OpenID Connect (OIDC) authentication
  • -
  • Internal users management
  • -
  • LDAP authentication
  • -
  • JWT authentication
  • -
  • OAuth 1.0a authentication
  • -
  • SAML V2 authentication
  • -
-

Certificates management

-
    -
  • Dynamic TLS certificates store
  • -
  • Dynamic TLS termination
  • -
  • Internal PKI
  • -
  • ACME / Let’s Encrypt support
  • -
  • On-the-fly certificate generation based on a CA certificate without request loss
  • -
-

Performances and testing

-
    -
  • Chaos engineering
  • -
  • Clustering with encrypted communication
  • -
  • Scalability
  • -
-

Kubernetes integration

-
    -
  • Standard Ingress controller
  • -
  • Custom Ingress controller -
      -
    • Manage Otoroshi resources from Kubernetes
    • -
    -
  • -
  • Validation of resources via webhook
  • -
  • Service Mesh for easy service-to-service communication
  • -
-

Developpers portal

- - -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/getting-started.html b/docs/manual/getting-started.html deleted file mode 100644 index 0b00c0dcbd..0000000000 --- a/docs/manual/getting-started.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - -Getting Started · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Getting Started

- -

Download the latest jar of Otoroshi

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

Once downloading, run Otoroshi.

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Protect the access to your api with the Otoroshi management of api keys

-

Create a service, exposed on http://myapi.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
--d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"myapi","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myapi","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":[""],"privatePatterns":["\/.*"],"kind":"ServiceDescriptor"}' \
--H "Content-type: application/json" \
--u admin-api-apikey-id:admin-api-apikey-secret
-
-

Try to call this service. You should receive an error from Otoroshi about a missing api key in our request.

-
curl 'http://myapi.oto.tools:8080'
-
-

Create your first api key with a quota of 10 calls by day and month.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/apikeys' \
--H "Content-type: application/json" \
--u admin-api-apikey-id:admin-api-apikey-secret \
--d @- <<'EOF'
-{
-    "clientId": "my-first-apikey-id",
-    "clientSecret": "my-first-apikey-secret",
-    "clientName": "my-first-apikey",
-    "description": "my-first-apikey-description",
-    "authorizedGroup": "default",
-    "enabled": true,
-    "throttlingQuota": 10,
-    "dailyQuota": 10,
-    "monthlyQuota": 10
-}
-EOF
-
-

Call your api with the generated apikey.

-
curl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret
-
-
{
-  "method": "GET",
-  "path": "/",
-  "headers": {
-    "host": "mirror.otoroshi.io",
-    "accept": "*/*",
-    "user-agent": "curl/7.64.1",
-    "authorization": "Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==",
-    "otoroshi-request-id": "1465298507974836306",
-    "otoroshi-proxied-host": "myapi.oto.tools:8080",
-    "otoroshi-request-timestamp": "2021-11-29T13:36:02.888+01:00",
-  },
-  "body": ""
-}
-
-

Check your remaining quotas

-
curl 'http://myapi.oto.tools:8080' -u my-first-apikey-id:my-first-apikey-secret --include
-
-

This should output these following Otoroshi headers

-
Otoroshi-Daily-Calls-Remaining: 6
-Otoroshi-Monthly-Calls-Remaining: 6
-
-

Keep calling the api and confirm that Otoroshi is sending you an apikey exceeding quota error

-
{ 
-    "Otoroshi-Error": "You performed too much requests"
-}
-
-

Well done, you have secured your first api with the apikeys system with limited call quotas.

-

Secure your web app in 5 minutes with an authentication

-

Create an in-memory authentication module, with one registered user, to protect your service.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/auths' \
--H "Otoroshi-Client-Id: admin-api-apikey-id" \
--H "Otoroshi-Client-Secret: admin-api-apikey-secret" \
--H 'Content-Type: application/json; charset=utf-8' \
--d @- <<'EOF'
-{
-    "type":"basic",
-    "id":"auth_mod_in_memory_auth",
-    "name":"in-memory-auth",
-    "desc":"in-memory-auth",
-    "users":[
-        {
-            "name":"User Otoroshi",
-            "password":"$2a$10$oIf4JkaOsfiypk5ZK8DKOumiNbb2xHMZUkYkuJyuIqMDYnR/zXj9i",
-            "email":"user@foo.bar",
-            "metadata":{
-                "username":"roger"
-            },
-            "tags":["foo"],
-            "webauthn":null,
-            "rights":[{
-                "tenant":"*:r",
-                "teams":["*:r"]
-            }]
-        }
-    ],
-    "sessionCookieValues":{
-        "httpOnly":true,
-        "secure":false
-    }
-}
-EOF
-
-

Then create a service secure by the previous authentication module, which proxies google.fr on webapp.oto.tools.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
--d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"webapp","description":"a service","env":"prod","domain":"oto.tools","subdomain":"webapp","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"google.fr","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[""],"kind":"ServiceDescriptor","authConfigRef":"auth_mod_in_memory_auth","privateApp":true}' \
--H "Content-type: application/json" \
--u admin-api-apikey-id:admin-api-apikey-secret
-
-

Navigate to http://webapp.oto.tools:8080, login with user@foo.bar/password and check that you’re redirect to google page.

-

Well done! You completed the discovery tutorial.

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/custom-initial-state.html b/docs/manual/how-to-s/custom-initial-state.html deleted file mode 100644 index ba367fffd7..0000000000 --- a/docs/manual/how-to-s/custom-initial-state.html +++ /dev/null @@ -1,392 +0,0 @@ - - - - -Initial state customization · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Initial state customization

-

when you start otoroshi for the first time, some basic entities will be created and stored in the datastore in order to make your instance work properly. However it might not be enough for your use case but you do want to bother with restoring a complete otoroshi export.

-

In order to make state customization easy, otoroshi provides the config. key otoroshi.initialCustomization, overriden by the env. variable OTOROSHI_INITIAL_CUSTOMIZATION

-

The expected structure is the following :

-
{
-  "config": { ... },
-  "admins": [],
-  "simpleAdmins": [],
-  "serviceGroups": [],
-  "apiKeys": [],
-  "serviceDescriptors": [],
-  "errorTemplates": [],
-  "jwtVerifiers": [],
-  "authConfigs": [],
-  "certificates": [],
-  "clientValidators": [],
-  "scripts": [],
-  "tcpServices": [],
-  "dataExporters": [],
-  "tenants": [],
-  "teams": []
-}
-
-

in this structure, everything is optional. For every array property, items will be added to the datastore. For the global config. object, you can just add the parts that you need, and they will be merged with the existing config. object of the datastore.

-

Customize the global config.

-

for instance, if you want to customize the behavior of the TLS termination, you can use the following :

-
export OTOROSHI_INITIAL_CUSTOMIZATION='{"config":{"tlsSettings":{"defaultDomain":"www.foo.bar","randomIfNotFound":false}}'
-
-

Customize entities

-

if you want to add apikeys at first boot

-
export OTOROSHI_INITIAL_CUSTOMIZATION='{"apikeys":[{"_loc":{"tenant":"default","teams":["default"]},"clientId":"ksVlQ2KlZm0CnDfP","clientSecret":"usZYbE1iwSsbpKY45W8kdbZySj1M5CWvFXe0sPbZ0glw6JalMsgorDvSBdr2ZVBk","clientName":"awesome-apikey","description":"the awesome apikey","authorizedGroup":"default","authorizedEntities":["group_default"],"enabled":true,"readOnly":false,"allowClientIdOnly":false,"throttlingQuota":10000000,"dailyQuota":10000000,"monthlyQuota":10000000,"constrainedServicesOnly":false,"restrictions":{"enabled":false,"allowLast":true,"allowed":[],"forbidden":[],"notFound":[]},"rotation":{"enabled":false,"rotationEvery":744,"gracePeriod":168,"nextSecret":null},"validUntil":null,"tags":[],"metadata":{}}]}'
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/custom-log-levels.html b/docs/manual/how-to-s/custom-log-levels.html deleted file mode 100644 index 7a64827505..0000000000 --- a/docs/manual/how-to-s/custom-log-levels.html +++ /dev/null @@ -1,552 +0,0 @@ - - - - -Log levels customization · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Log levels customization

-

If you want to customize the log level of your otoroshi instances, it’s pretty easy to do it using environment variables or configuration file.

-

Customize log level for one logger with configuration file

-

Let say you want to see DEBUG messages from the logger otoroshi-http-handler.

-

Then you just have to declare in your otoroshi configuration file

-
otoroshi.loggers {
-  ...
-  otoroshi-http-handler = "DEBUG"
-  ...
-}
-
-

possible levels are TRACE, DEBUG, INFO, WARN, ERROR. Default one is WARN.

-

Customize log level for one logger with environment variable

-

Let say you want to see DEBUG messages from the logger otoroshi-http-handler.

-

Then you just have to declare an environment variable named OTOROSHI_LOGGERS_OTOROSHI_HTTP_HANDLER with value DEBUG. The rule is

-
"OTOROSHI_LOGGERS_" + loggerName.toUpperCase().replace("-", "_")
-
-

possible levels are TRACE, DEBUG, INFO, WARN, ERROR. Default one is WARN.

-

List of loggers

- - -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/end-to-end-mtls.html b/docs/manual/how-to-s/end-to-end-mtls.html deleted file mode 100644 index b56801fec5..0000000000 --- a/docs/manual/how-to-s/end-to-end-mtls.html +++ /dev/null @@ -1,646 +0,0 @@ - - - - -End-to-end mTLS · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

End-to-end mTLS

-

If you want to use MTLS on otoroshi, you first need to enable it. It is not enabled by default as it will make TLS handshake way heavier. To enable it just change the following config :

-
otoroshi.ssl.fromOutside.clientAuth=None|Want|Need
-
-

or using env. variables

-
SSL_OUTSIDE_CLIENT_AUTH=None|Want|Need
-
-

You can use the Want setup if you cant to have both mtls on some services and no mtls on other services.

-

You can also change the trusted CA list sent in the handshake certificate request from the Danger Zone in Tls Settings.

-

Otoroshi support mutual TLS out of the box. mTLS from client to Otoroshi and from Otoroshi to targets are supported. In this article we will see how to configure Otoroshi to use end-to-end mTLS. All code and files used in this articles can be found on the Otoroshi github

-

Create certificates

-

But first we need to generate some certificates to make the demo work

-
mkdir mtls-demo
-cd mtls-demo
-mkdir ca
-mkdir server
-mkdir client
-
-# create a certificate authority key, use password as pass phrase
-openssl genrsa -out ./ca/ca-backend.key 4096
-# remove pass phrase
-openssl rsa -in ./ca/ca-backend.key -out ./ca/ca-backend.key
-# generate the certificate authority cert
-openssl req -new -x509 -sha256 -days 730 -key ./ca/ca-backend.key -out ./ca/ca-backend.cer -subj "/CN=MTLSB"
-
-
-# create a certificate authority key, use password as pass phrase
-openssl genrsa -out ./ca/ca-frontend.key 2048
-# remove pass phrase
-openssl rsa -in ./ca/ca-frontend.key -out ./ca/ca-frontend.key
-# generate the certificate authority cert
-openssl req -new -x509 -sha256 -days 730 -key ./ca/ca-frontend.key -out ./ca/ca-frontend.cer -subj "/CN=MTLSF"
-
-
-# now create the backend cert key, use password as pass phrase
-openssl genrsa -out ./server/_.backend.oto.tools.key 2048
-# remove pass phrase
-openssl rsa -in ./server/_.backend.oto.tools.key -out ./server/_.backend.oto.tools.key
-# generate the csr for the certificate
-openssl req -new -key ./server/_.backend.oto.tools.key -sha256 -out ./server/_.backend.oto.tools.csr -subj "/CN=*.backend.oto.tools"
-# generate the certificate
-openssl x509 -req -days 365 -sha256 -in ./server/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.oto.tools.cer
-# verify the certificate, should output './server/_.backend.oto.tools.cer: OK'
-openssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.oto.tools.cer
-
-
-# now create the frontend cert key, use password as pass phrase
-openssl genrsa -out ./server/_.frontend.oto.tools.key 2048
-# remove pass phrase
-openssl rsa -in ./server/_.frontend.oto.tools.key -out ./server/_.frontend.oto.tools.key
-# generate the csr for the certificate
-openssl req -new -key ./server/_.frontend.oto.tools.key -sha256 -out ./server/_.frontend.oto.tools.csr -subj "/CN=*.frontend.oto.tools"
-# generate the certificate
-openssl x509 -req -days 365 -sha256 -in ./server/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.oto.tools.cer
-# verify the certificate, should output './server/_.frontend.oto.tools.cer: OK'
-openssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.cer
-
-
-# now create the client cert key for backend, use password as pass phrase
-openssl genrsa -out ./client/_.backend.oto.tools.key 2048
-# remove pass phrase
-openssl rsa -in ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.key
-# generate the csr for the certificate
-openssl req -new -key ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.csr -subj "/CN=*.backend.oto.tools"
-# generate the certificate
-openssl x509 -req -days 365 -sha256 -in ./client/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.oto.tools.cer
-# generate a pem version of the cert and key, use password as password
-openssl x509 -in client/_.backend.oto.tools.cer -out client/_.backend.oto.tools.pem -outform PEM
-
-
-# now create the client cert key for frontend, use password as pass phrase
-openssl genrsa -out ./client/_.frontend.oto.tools.key 2048
-# remove pass phrase
-openssl rsa -in ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.key
-# generate the csr for the certificate
-openssl req -new -key ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.csr -subj "/CN=*.frontend.oto.tools"
-# generate the certificate
-openssl x509 -req -days 365 -sha256 -in ./client/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.oto.tools.cer
-# generate a pkcs12 version of the cert and key, use password as password
-# openssl pkcs12 -export -clcerts -in client/_.frontend.oto.tools.cer -inkey client/_.frontend.oto.tools.key -out client/_.frontend.oto.tools.p12
-openssl x509 -in client/_.frontend.oto.tools.cer -out client/_.frontend.oto.tools.pem -outform PEM
-
-

Once it’s done, you should have something like

-
$ tree
-.
-├── backend.js
-├── ca
-│   ├── ca-backend.cer
-│   ├── ca-backend.key
-│   ├── ca-frontend.cer
-│   └── ca-frontend.key
-├── client
-│   ├── _.backend.oto.tools.cer
-│   ├── _.backend.oto.tools.csr
-│   ├── _.backend.oto.tools.key
-│   ├── _.backend.oto.tools.pem
-│   ├── _.frontend.oto.tools.cer
-│   ├── _.frontend.oto.tools.csr
-│   ├── _.frontend.oto.tools.key
-│   └── _.frontend.oto.tools.pem
-└── server
-    ├── _.backend.oto.tools.cer
-    ├── _.backend.oto.tools.csr
-    ├── _.backend.oto.tools.key
-    ├── _.frontend.oto.tools.cer
-    ├── _.frontend.oto.tools.csr
-    └── _.frontend.oto.tools.key
-
-3 directories, 18 files
-
-

The backend service

-

now, let’s create a backend service using nodejs. Create a file named backend.js

-
touch backend.js
-
-

and put the following content

-
const fs = require('fs'); 
-const https = require('https'); 
-
-const options = { 
-  key: fs.readFileSync('./server/_.backend.oto.tools.key'), 
-  cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), 
-  ca: fs.readFileSync('./ca/ca-backend.cer'), 
-}; 
-
-const server = https.createServer(options, (req, res) => { 
-  res.writeHead(200, {
-    'Content-Type': 'application/json'
-  }); 
-  res.end(JSON.stringify({ message: 'Hello World!' }) + "\n"); 
-}).listen(8444);
-
-console.log('Server listening:', `http://localhost:${server.address().port}`);
-
-

to run the server, just do

-
node ./backend.js
-
-

now you can try your server with

-
curl --cacert ./ca/ca-backend.cer 'https://api.backend.oto.tools:8444/'
-
-

This should output :

-
{ "message": "Hello World!" }
-
-

now modify your backend server to ensure that the client provides a client certificate like:

-
const fs = require('fs'); 
-const https = require('https'); 
-
-const options = { 
-  key: fs.readFileSync('./server/_.backend.oto.tools.key'), 
-  cert: fs.readFileSync('./server/_.backend.oto.tools.cer'), 
-  ca: fs.readFileSync('./ca/ca-backend.cer'), 
-  requestCert: true, 
-  rejectUnauthorized: true
-}; 
-
-const server = https.createServer(options, (req, res) => { 
-  console.log('Client certificate CN: ', req.socket.getPeerCertificate().subject.CN);
-  res.writeHead(200, {
-    'Content-Type': 'application/json'
-  }); 
-  res.end(JSON.stringify({ message: 'Hello World!' }) + "\n"); 
-}).listen(8444);
-
-console.log('Server listening:', `http://localhost:${server.address().port}`);
-
-

you can test your new server with

-
curl \
-  --cacert ./ca/ca-backend.cer \
-  --cert ./client/_.backend.oto.tools.pem \
-  --key ./client/_.backend.oto.tools.key 'https://api.backend.oto.tools:8444/'
-
-

the output should be :

-
{ "message": "Hello World!" }
-
-

Otoroshi setup

-

Download the latest version of the Otoroshi jar and run it like

-
 java \
-  -Dotoroshi.adminPassword=password \
-  -Dotoroshi.ssl.fromOutside.clientAuth=Want \
-  -jar -Dotoroshi.storage=file otoroshi.jar
-
-[info] otoroshi-env - Admin API exposed on http://otoroshi-api.oto.tools:8080
-[info] otoroshi-env - Admin UI  exposed on http://otoroshi.oto.tools:8080
-[info] otoroshi-in-memory-datastores - Now using InMemory DataStores
-[info] otoroshi-env - The main datastore seems to be empty, registering some basic services
-[info] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / password
-[info] play.api.Play - Application started (Prod)
-[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080
-[info] p.c.s.AkkaHttpServer - Listening for HTTPS on /0:0:0:0:0:0:0:0:8443
-[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...
-
-

and log into otoroshi with the tuple admin@otoroshi.io / password displayed in the logs.

-

Once logged in, navigate to the services pages and create a new item.

-
    -
  • Jump to the Service exposition settings and add http://api.frontend.oto.tools as Exposed domain.
  • -
  • Navigate to the Service targets and add the following url https://api.backend.oto.tools:8444/ to redirect our call to the previous created backend.
  • -
  • End this step by exposing the service as Public UI on the URL Patterns section.
  • -
-

and test it

-
curl 'http://api.frontend.oto.tools:8080/'
-
-

This should output :

-
{"Otoroshi-Error": "Something went wrong, you should try later. Thanks for your understanding."}
-
-

you should get an error due to the fact that Otoroshi doesn’t know about the server certificate or the client certificate expected by the server.

-

We have to add the client certificate for https://api.backend.oto.tools to Otoroshi.

-

Go to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of ./client/_.backend.oto.tools.cer and ./client/_.backend.oto.tools.key respectively in Certificate full chain and Certificate private key.

-

If you don’t want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.

-
cat ./server/_.backend.oto.tools.cer ./ca/ca-backend.cer ./server/_.backend.oto.tools.key | curl \
-  -H 'Content-Type: text/plain' -X POST \
-  --data-binary @- \
-  -u admin-api-apikey-id:admin-api-apikey-secret \
-  http://otoroshi-api.oto.tools:8080/api/certificates/_bundle 
-
-

and retry the following curl command

-
curl 'http://api.frontend.oto.tools:8080/'
-
-

the output should be

-
{"message":"Hello World!"}
-
-

now we have to expose https://api.frontend.oto.tools:8443 using otoroshi.

-

Go to http://otoroshi.oto.tools:8080/bo/dashboard/certificates and create a new item. Copy and paste the content of ./server/_.frontend.oto.tools.cer and ./server/_.frontend.oto.tools.key respectively in Certificate full chain and Certificate private key.

-

If you don’t want to bother with UI copy/paste, you can use the import bundle api endpoint to create an otoroshi certificate automatically from a PEM bundle.

-
cat ./server/_.frontend.oto.tools.cer ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.key | curl \
-  -H 'Content-Type: text/plain' -X POST \
-  -u admin-api-apikey-id:admin-api-apikey-secret \
-  --data-binary @- \
-  http://otoroshi-api.oto.tools:8080/api/certificates/_bundle
-
-

and try the following command

-
curl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'
-
-

the output should be

-
{"message":"Hello World!"}
-
-

now we have to enforce the fact that we want client certificate for api.frontend.oto.tools. To do that, we have to add a Client Validator Only plugin on the api.frontend.oto.tools service. Scroll to the last section called Plugins and select the Client validator only in the list.

-

now if you retry

-
curl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'
-
-

the output should be

-
{"Otoroshi-Error":"bad request"}
-
-

you should get an error because no client cert. is passed with the request. But if you pass the ./client/_.frontend.oto.tools.csr client cert and the key in your curl call

-
curl 'https://api.frontend.oto.tools:8443' \
-  --cacert ./ca/ca-frontend.cer \
-  --cert ./client/_.frontend.oto.tools.pem \
-  --key ./client/_.frontend.oto.tools.key
-
-

the output should be

-
{"message":"Hello World!"}
-
-

Client certificate matching plugin

-

Otoroshi can restrict and check all incoming client certificates on a service.

-

Scroll to the Plugins section and select the Client certificate matching plugin. Then, click on the show config. panel and inject the default configuration of the plugin (by clicking on Inject default config.).

-

Save the service and retry your call again.

-
curl 'https://api.frontend.oto.tools:8443' \
-  --cacert ./ca/ca-frontend.cer \
-  --cert ./client/_.frontend.oto.tools.pem \
-  --key ./client/_.frontend.oto.tools.key
-
-

the output should be

-
{"Otoroshi-Error":"bad request"}
-
-

Our client certificate is not matched by Otoroshi. We have to add the subject DN in the configuration of the Client certificate matching plugin to authorize it.

-
{
-  "HasClientCertMatchingValidator": {
-    "serialNumbers": [],
-    "subjectDNs": [
-      "CN=*.frontend.oto.tools"
-    ],
-    "issuerDNs": [],
-    "regexSubjectDNs": [],
-    "regexIssuerDNs": []
-  }
-}
-
-

Save the service and retry your call again.

-
curl 'https://api.frontend.oto.tools:8443' \
-  --cacert ./ca/ca-frontend.cer \
-  --cert ./client/_.frontend.oto.tools.pem \
-  --key ./client/_.frontend.oto.tools.key
-
-

the output should be

-
{"message":"Hello World!"}
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/export-alerts-using-mailgun.html b/docs/manual/how-to-s/export-alerts-using-mailgun.html deleted file mode 100644 index 602e7005a1..0000000000 --- a/docs/manual/how-to-s/export-alerts-using-mailgun.html +++ /dev/null @@ -1,399 +0,0 @@ - - - - -Send alerts using mailgun · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Send alerts using mailgun

-

All Otoroshi alerts can be send on different channels. One of the ways is to send a group of specific alerts via emails.

-

To enable this behaviour, let’s start by create an exporter of events.

-

In this tutorial, we will admit that you already have a mailgun account with an API key and a domain.

-

Create an Mailgun exporter

-

Let’s create an exporter. The exporter will export by default all events generated by Otoroshi.

-
    -
  1. Go ahead, and navigate to http://otoroshi.oto.tools:8080
  2. -
  3. Click on the cog icon on the top right
  4. -
  5. Then Exporters button
  6. -
  7. And add a new configuration when clicking on the Add item button
  8. -
  9. Select the mailer in the type selector field
  10. -
  11. Jump to Exporter config and select the Mailgun option
  12. -
  13. Set the following values:
  14. -
-
    -
  • EU : false/true depending on your mailgun configuratin
  • -
  • Mailgun api key : your-mailgun-api-key
  • -
  • Mailgun domain : your-mailgun-domain
  • -
  • Email addresses : list of the recipient adresses
  • -
-

With this configuration, all Otoroshi events will be send to your listed addresses (we don’t recommended to do that).

-

To filter events on Alerts type, we need to add the following configuration inside the Filtering and projection section (if you want to deep learn about this section, read this part).

-
{
-    "include": [
-        { "@type": "AlertEvent" }
-    ],
-    "exclude": []
-}
-
-

Save at the bottom page and enable the exporter (on the top of the page or in list of exporters). We will need to wait few seconds to receive the first alerts.

-

The projection field can be useful in the case you want to filter the fields contained in each alert sent.

-

The Projection field is a json where you can list the fields to keep for each alert.

-
{
- "@type": true,
- "@timestamp": true,
- "@id": true
-}
-
-

With this example, only @type, @timestamp and @id will be sent to the addresses of your recipients.

- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/export-events-to-elastic.html b/docs/manual/how-to-s/export-events-to-elastic.html deleted file mode 100644 index aa1f34f600..0000000000 --- a/docs/manual/how-to-s/export-events-to-elastic.html +++ /dev/null @@ -1,451 +0,0 @@ - - - - -Export events to Elasticsearch · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Export events to Elasticsearch

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Deploy a Elasticsearch and kibana stack on Docker

-

Let’s start by creating an Elasticsearch and Kibana stack on our machine (if it’s already done for you, you can skip this section).

-

To start an Elasticsearch container for development or testing, run:

-
docker network create elastic
-docker pull docker.elastic.co/elasticsearch/elasticsearch:7.15.1
-docker run --name es01-test --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.15.1
-
-
docker pull docker.elastic.co/kibana/kibana:7.15.1
-docker run --name kib01-test --net elastic -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://es01-test:9200" docker.elastic.co/kibana/kibana:7.15.1
-
-

To access Kibana, go to http://localhost:5601.

-

Create an Elasticsearch exporter

-

Let’s create an exporter. The exporter will export by default all events generated by Otoroshi.

-
    -
  1. Go ahead, and navigate to http://otoroshi.oto.tools:8080
  2. -
  3. Click on the cog icon on the top right
  4. -
  5. Then Exporters button
  6. -
  7. And add a new configuration when clicking on the Add item button
  8. -
  9. Select the elastic in the type selector field
  10. -
  11. Jump to Exporter config
  12. -
  13. Set the following values: Cluster URI -> http://localhost:9200
  14. -
-

Then test your configuration by clicking on the Check connection button. This should output a modal with the Elasticsearch version and the number of loaded docs.

-

Save at the bottom of the page and enable the exporter (on the top of the page or in list of exporters).

-

Testing your configuration

-

One simple way to test is to setup the reading of our Elasticsearch instance by Otoroshi.

-

Navigate to the danger zone (click on the cog on the top right and scroll to danger zone). Jump to the Analytics: Elastic dashboard datasource (read) section.

-

Set the following values : Cluster URI -> http://localhost:9200

-

Then click on the Check connection. This should ouput the same result as the previous part. Save the global configuration and navigate to http://otoroshi.oto.tools:8080/bo/dashboard/stats.

-

This should output a list of graphs.

-

Advanced usage

-

By default, an exporter handle all events from Otoroshi. In some case, you need to filter the events to send to elasticsearch.

-

To filter the events, jump to the Filtering and projection field in exporter view. Otoroshi supports to include a kind of events or to exclude a list of events (if you want to deep learn about this section, read this part).

-

An example which keep only events with a field @type of value AlertEvent:

-
{
-    "include": [
-        { "@type": "AlertEvent" }
-    ],
-    "exclude": []
-}
-
-

An example which exclude only events with a field @type of value GatewayEvent :

-
{
-    "exclude": [
-        { "@type": "GatewayEvent" }
-    ],
-    "include": []
-}
-
-

The next field is the Projection. This field is a json when you can list the fields to keep for each event.

-
{
- "@type": true,
- "@timestamp": true,
- "@id": true
-}
-
-

With this example, only @type, @timestamp and @id will be send to ES.

-

Debug your configuration

-

Missing user rights on Elasticsearch

-

When creating an exporter, Otoroshi try to join the index route of the elasticsearch instance. If you have a specific management access rights on Elasticsearch, you have two possiblities :

-
    -
  • set a full access to the user used in Otoroshi for write in Elasticsearch
  • -
  • set the version of Elasticsearch inside the Version field of your exporter.
  • -
-

None event appear in your Elasticsearch

-

When creating an exporter, Otoroshi try to push the index template on Elasticsearch. If the post failed, Otoroshi will fail for each push of events and your database will keep empty.

-

To fix this problem, you can try to send the index template with the Manually apply index template button in your exporter.

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/import-export-otoroshi-datastore.html b/docs/manual/how-to-s/import-export-otoroshi-datastore.html deleted file mode 100644 index 9bd4ebacad..0000000000 --- a/docs/manual/how-to-s/import-export-otoroshi-datastore.html +++ /dev/null @@ -1,1333 +0,0 @@ - - - - -Import and export Otoroshi datastore · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Import and export Otoroshi datastore

-

Start Otoroshi with an initial datastore

-

Let’s start by downloading the latest Otoroshi

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

By default, Otoroshi starts with domain oto.tools that targets 127.0.0.1 Now you are almost ready to run Otoroshi for the first time, we want run it with an initial data.

-

To do that, you need to add the otoroshi.importFrom setting to the Otoroshi configuration (of $APP_IMPORT_FROM env). It can be a file path or a URL. The content of the initial datastore can look something like the following.

-
{
-  "label": "Otoroshi initial datastore",
-  "admins": [],
-  "simpleAdmins": [
-    {
-      "_loc": {
-        "tenant": "default",
-        "teams": [
-          "default"
-        ]
-      },
-      "username": "admin@otoroshi.io",
-      "password": "$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.",
-      "label": "Otoroshi Admin",
-      "createdAt": 1634651307724,
-      "type": "SIMPLE",
-      "metadata": {},
-      "tags": [],
-      "rights": [
-        {
-          "tenant": "*:rw",
-          "teams": [
-            "*:rw"
-          ]
-        }
-      ]
-    }
-  ],
-  "serviceGroups": [
-    {
-      "_loc": {
-        "tenant": "default",
-        "teams": [
-          "default"
-        ]
-      },
-      "id": "admin-api-group",
-      "name": "Otoroshi Admin Api group",
-      "description": "No description",
-      "tags": [],
-      "metadata": {}
-    },
-    {
-      "_loc": {
-        "tenant": "default",
-        "teams": [
-          "default"
-        ]
-      },
-      "id": "default",
-      "name": "default-group",
-      "description": "The default service group",
-      "tags": [],
-      "metadata": {}
-    }
-  ],
-  "apiKeys": [
-    {
-      "_loc": {
-        "tenant": "default",
-        "teams": [
-          "default"
-        ]
-      },
-      "clientId": "admin-api-apikey-id",
-      "clientSecret": "admin-api-apikey-secret",
-      "clientName": "Otoroshi Backoffice ApiKey",
-      "description": "The apikey use by the Otoroshi UI",
-      "authorizedGroup": "admin-api-group",
-      "authorizedEntities": [
-        "group_admin-api-group"
-      ],
-      "enabled": true,
-      "readOnly": false,
-      "allowClientIdOnly": false,
-      "throttlingQuota": 10000,
-      "dailyQuota": 10000000,
-      "monthlyQuota": 10000000,
-      "constrainedServicesOnly": false,
-      "restrictions": {
-        "enabled": false,
-        "allowLast": true,
-        "allowed": [],
-        "forbidden": [],
-        "notFound": []
-      },
-      "rotation": {
-        "enabled": false,
-        "rotationEvery": 744,
-        "gracePeriod": 168,
-        "nextSecret": null
-      },
-      "validUntil": null,
-      "tags": [],
-      "metadata": {}
-    }
-  ],
-  "serviceDescriptors": [
-    {
-      "_loc": {
-        "tenant": "default",
-        "teams": [
-          "default"
-        ]
-      },
-      "id": "admin-api-service",
-      "groupId": "admin-api-group",
-      "groups": [
-        "admin-api-group"
-      ],
-      "name": "otoroshi-admin-api",
-      "description": "",
-      "env": "prod",
-      "domain": "oto.tools",
-      "subdomain": "otoroshi-api",
-      "targetsLoadBalancing": {
-        "type": "RoundRobin"
-      },
-      "targets": [
-        {
-          "host": "127.0.0.1:8080",
-          "scheme": "http",
-          "weight": 1,
-          "mtlsConfig": {
-            "certs": [],
-            "trustedCerts": [],
-            "mtls": false,
-            "loose": false,
-            "trustAll": false
-          },
-          "tags": [],
-          "metadata": {},
-          "protocol": "HTTP/1.1",
-          "predicate": {
-            "type": "AlwaysMatch"
-          },
-          "ipAddress": null
-        }
-      ],
-      "root": "/",
-      "matchingRoot": null,
-      "stripPath": true,
-      "localHost": "127.0.0.1:8080",
-      "localScheme": "http",
-      "redirectToLocal": false,
-      "enabled": true,
-      "userFacing": false,
-      "privateApp": false,
-      "forceHttps": false,
-      "logAnalyticsOnServer": false,
-      "useAkkaHttpClient": true,
-      "useNewWSClient": false,
-      "tcpUdpTunneling": false,
-      "detectApiKeySooner": false,
-      "maintenanceMode": false,
-      "buildMode": false,
-      "strictlyPrivate": false,
-      "enforceSecureCommunication": true,
-      "sendInfoToken": true,
-      "sendStateChallenge": true,
-      "sendOtoroshiHeadersBack": true,
-      "readOnly": false,
-      "xForwardedHeaders": false,
-      "overrideHost": true,
-      "allowHttp10": true,
-      "letsEncrypt": false,
-      "secComHeaders": {
-        "claimRequestName": null,
-        "stateRequestName": null,
-        "stateResponseName": null
-      },
-      "secComTtl": 30000,
-      "secComVersion": 1,
-      "secComInfoTokenVersion": "Legacy",
-      "secComExcludedPatterns": [],
-      "securityExcludedPatterns": [],
-      "publicPatterns": [
-        "/health",
-        "/metrics"
-      ],
-      "privatePatterns": [],
-      "additionalHeaders": {
-        "Host": "otoroshi-admin-internal-api.oto.tools"
-      },
-      "additionalHeadersOut": {},
-      "missingOnlyHeadersIn": {},
-      "missingOnlyHeadersOut": {},
-      "removeHeadersIn": [],
-      "removeHeadersOut": [],
-      "headersVerification": {},
-      "matchingHeaders": {},
-      "ipFiltering": {
-        "whitelist": [],
-        "blacklist": []
-      },
-      "api": {
-        "exposeApi": false
-      },
-      "healthCheck": {
-        "enabled": false,
-        "url": "/"
-      },
-      "clientConfig": {
-        "useCircuitBreaker": true,
-        "retries": 1,
-        "maxErrors": 20,
-        "retryInitialDelay": 50,
-        "backoffFactor": 2,
-        "callTimeout": 30000,
-        "callAndStreamTimeout": 120000,
-        "connectionTimeout": 10000,
-        "idleTimeout": 60000,
-        "globalTimeout": 30000,
-        "sampleInterval": 2000,
-        "proxy": {},
-        "customTimeouts": [],
-        "cacheConnectionSettings": {
-          "enabled": false,
-          "queueSize": 2048
-        }
-      },
-      "canary": {
-        "enabled": false,
-        "traffic": 0.2,
-        "targets": [],
-        "root": "/"
-      },
-      "gzip": {
-        "enabled": false,
-        "excludedPatterns": [],
-        "whiteList": [
-          "text/*",
-          "application/javascript",
-          "application/json"
-        ],
-        "blackList": [],
-        "bufferSize": 8192,
-        "chunkedThreshold": 102400,
-        "compressionLevel": 5
-      },
-      "metadata": {},
-      "tags": [],
-      "chaosConfig": {
-        "enabled": false,
-        "largeRequestFaultConfig": null,
-        "largeResponseFaultConfig": null,
-        "latencyInjectionFaultConfig": null,
-        "badResponsesFaultConfig": null
-      },
-      "jwtVerifier": {
-        "type": "ref",
-        "ids": [],
-        "id": null,
-        "enabled": false,
-        "excludedPatterns": []
-      },
-      "secComSettings": {
-        "type": "HSAlgoSettings",
-        "size": 512,
-        "secret": "secret",
-        "base64": false
-      },
-      "secComUseSameAlgo": true,
-      "secComAlgoChallengeOtoToBack": {
-        "type": "HSAlgoSettings",
-        "size": 512,
-        "secret": "secret",
-        "base64": false
-      },
-      "secComAlgoChallengeBackToOto": {
-        "type": "HSAlgoSettings",
-        "size": 512,
-        "secret": "secret",
-        "base64": false
-      },
-      "secComAlgoInfoToken": {
-        "type": "HSAlgoSettings",
-        "size": 512,
-        "secret": "secret",
-        "base64": false
-      },
-      "cors": {
-        "enabled": false,
-        "allowOrigin": "*",
-        "exposeHeaders": [],
-        "allowHeaders": [],
-        "allowMethods": [],
-        "excludedPatterns": [],
-        "maxAge": null,
-        "allowCredentials": true
-      },
-      "redirection": {
-        "enabled": false,
-        "code": 303,
-        "to": "https://www.otoroshi.io"
-      },
-      "authConfigRef": null,
-      "clientValidatorRef": null,
-      "transformerRef": null,
-      "transformerRefs": [],
-      "transformerConfig": {},
-      "apiKeyConstraints": {
-        "basicAuth": {
-          "enabled": true,
-          "headerName": null,
-          "queryName": null
-        },
-        "customHeadersAuth": {
-          "enabled": true,
-          "clientIdHeaderName": null,
-          "clientSecretHeaderName": null
-        },
-        "clientIdAuth": {
-          "enabled": true,
-          "headerName": null,
-          "queryName": null
-        },
-        "jwtAuth": {
-          "enabled": true,
-          "secretSigned": true,
-          "keyPairSigned": true,
-          "includeRequestAttributes": false,
-          "maxJwtLifespanSecs": null,
-          "headerName": null,
-          "queryName": null,
-          "cookieName": null
-        },
-        "routing": {
-          "noneTagIn": [],
-          "oneTagIn": [],
-          "allTagsIn": [],
-          "noneMetaIn": {},
-          "oneMetaIn": {},
-          "allMetaIn": {},
-          "noneMetaKeysIn": [],
-          "oneMetaKeyIn": [],
-          "allMetaKeysIn": []
-        }
-      },
-      "restrictions": {
-        "enabled": false,
-        "allowLast": true,
-        "allowed": [],
-        "forbidden": [],
-        "notFound": []
-      },
-      "accessValidator": {
-        "enabled": false,
-        "refs": [],
-        "config": {},
-        "excludedPatterns": []
-      },
-      "preRouting": {
-        "enabled": false,
-        "refs": [],
-        "config": {},
-        "excludedPatterns": []
-      },
-      "plugins": {
-        "enabled": false,
-        "refs": [],
-        "config": {},
-        "excluded": []
-      },
-      "hosts": [
-        "otoroshi-api.oto.tools"
-      ],
-      "paths": [],
-      "handleLegacyDomain": true,
-      "issueCert": false,
-      "issueCertCA": null
-    }
-  ],
-  "errorTemplates": [],
-  "jwtVerifiers": [],
-  "authConfigs": [],
-  "certificates": [],
-  "clientValidators": [],
-  "scripts": [],
-  "tcpServices": [],
-  "dataExporters": [],
-  "tenants": [
-    {
-      "id": "default",
-      "name": "Default organization",
-      "description": "The default organization",
-      "metadata": {},
-      "tags": []
-    }
-  ],
-  "teams": [
-    {
-      "id": "default",
-      "tenant": "default",
-      "name": "Default Team",
-      "description": "The default Team of the default organization",
-      "metadata": {},
-      "tags": []
-    }
-  ]
-}
-
-

Run an Otoroshi with the previous file as parameter.

-
java \
-  -Dotoroshi.adminPassword=password \
-  -Dotoroshi.importFrom=./initial-state.json \
-  -jar otoroshi.jar 
-
-

This should display

-
...
-[info] otoroshi-env - Importing from: ./initial-state.json
-[info] otoroshi-env - Successful import !
-...
-[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080
-...
-
-
-

Warning : when you using Otoroshi with a datastore different from file or in-memory, Otoroshi will not reload the initialization script. If you expected, you have to manually clean your store.

-
-

Export the current datastore via the danger zone

-

When Otoroshi is running, you can backup the global configuration store from the UI. Navigate to your instance (in our case http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) and scroll to the bottom page.

-

Click on Full export button to download the full global configuration.

-

Import a datastore from file via the danger zone

-

When Otoroshi is running, you can recover a global configuration from the UI. Navigate to your instance (in our case http://otoroshi.oto.tools:8080/bo/dashboard/dangerzone) and scroll to the bottom of the page.

-

Click on Recover from a full export file button to apply all configurations from a file.

-

Export the current datastore with the Admin API

-

Otoroshi exposes his own Admin API to manage Otoroshi resources. To call this api, you need to have an api key with the rights on Otoroshi Admin Api group. This group includes the Otoroshi-admin-api service that you can found on the services page.

-

By default, and with our initial configuration, Otoroshi has already created an api key named Otoroshi Backoffice ApiKey. You can verify the rights of an api key on its page by checking the Authorized On field (you should find the Otoroshi Admin Api group inside).

-

The default api key id and secret are admin-api-apikey-id and admin-api-apikey-secret.

-

Run the next command with these values.

-
curl \
-  -H 'Content-Type: application/json' \
-  -u admin-api-apikey-id:admin-api-apikey-secret \
-  'http://otoroshi-api.oto.tools:8080/api/otoroshi.json'
-
-

When calling the /api/otoroshi.json, the return should be the current datastore including the service descriptors, the api keys, all others resources like certificates and authentification modules, and the the global config (representing the form of the danger zone).

-

Import the current datastore with the Admin API

-

As the same way of previous section, you can erase the current datastore with a POST request. The route is the same : /api/otoroshi.json.

-
curl \
-  -X POST \
-  -H 'Content-Type: application/json' \
-  -d '{
-    "label" : "Otoroshi export",
-    "dateRaw" : 1634714811217,
-    "date" : "2021-10-20 09:26:51",
-    "stats" : {
-      "calls" : 4,
-      "dataIn" : 0,
-      "dataOut" : 97991
-    },
-    "config" : {
-      "tags" : [ ],
-      "letsEncryptSettings" : {
-        "enabled" : false,
-        "server" : "acme://letsencrypt.org/staging",
-        "emails" : [ ],
-        "contacts" : [ ],
-        "publicKey" : "",
-        "privateKey" : ""
-      },
-      "lines" : [ "prod" ],
-      "maintenanceMode" : false,
-      "enableEmbeddedMetrics" : true,
-      "streamEntityOnly" : true,
-      "autoLinkToDefaultGroup" : true,
-      "limitConcurrentRequests" : false,
-      "maxConcurrentRequests" : 1000,
-      "maxHttp10ResponseSize" : 4194304,
-      "useCircuitBreakers" : true,
-      "apiReadOnly" : false,
-      "u2fLoginOnly" : false,
-      "trustXForwarded" : true,
-      "ipFiltering" : {
-        "whitelist" : [ ],
-        "blacklist" : [ ]
-      },
-      "throttlingQuota" : 10000000,
-      "perIpThrottlingQuota" : 10000000,
-      "analyticsWebhooks" : [ ],
-      "alertsWebhooks" : [ ],
-      "elasticWritesConfigs" : [ ],
-      "elasticReadsConfig" : null,
-      "alertsEmails" : [ ],
-      "logAnalyticsOnServer" : false,
-      "useAkkaHttpClient" : false,
-      "endlessIpAddresses" : [ ],
-      "statsdConfig" : null,
-      "kafkaConfig" : {
-        "servers" : [ ],
-        "keyPass" : null,
-        "keystore" : null,
-        "truststore" : null,
-        "topic" : "otoroshi-events",
-        "mtlsConfig" : {
-          "certs" : [ ],
-          "trustedCerts" : [ ],
-          "mtls" : false,
-          "loose" : false,
-          "trustAll" : false
-        }
-      },
-      "backOfficeAuthRef" : null,
-      "mailerSettings" : {
-        "type" : "none"
-      },
-      "cleverSettings" : null,
-      "maxWebhookSize" : 100,
-      "middleFingers" : false,
-      "maxLogsSize" : 10000,
-      "otoroshiId" : "83539cbca-76ee-4abc-ad31-a4794e873848",
-      "snowMonkeyConfig" : {
-        "enabled" : false,
-        "outageStrategy" : "OneServicePerGroup",
-        "includeUserFacingDescriptors" : false,
-        "dryRun" : false,
-        "timesPerDay" : 1,
-        "startTime" : "09:00:00.000",
-        "stopTime" : "23:59:59.000",
-        "outageDurationFrom" : 600000,
-        "outageDurationTo" : 3600000,
-        "targetGroups" : [ ],
-        "chaosConfig" : {
-          "enabled" : true,
-          "largeRequestFaultConfig" : null,
-          "largeResponseFaultConfig" : null,
-          "latencyInjectionFaultConfig" : {
-            "ratio" : 0.2,
-            "from" : 500,
-            "to" : 5000
-          },
-          "badResponsesFaultConfig" : {
-            "ratio" : 0.2,
-            "responses" : [ {
-              "status" : 502,
-              "body" : "{\"error\":\"Nihonzaru everywhere ...\"}",
-              "headers" : {
-                "Content-Type" : "application/json"
-              }
-            } ]
-          }
-        }
-      },
-      "scripts" : {
-        "enabled" : false,
-        "transformersRefs" : [ ],
-        "transformersConfig" : { },
-        "validatorRefs" : [ ],
-        "validatorConfig" : { },
-        "preRouteRefs" : [ ],
-        "preRouteConfig" : { },
-        "sinkRefs" : [ ],
-        "sinkConfig" : { },
-        "jobRefs" : [ ],
-        "jobConfig" : { }
-      },
-      "geolocationSettings" : {
-        "type" : "none"
-      },
-      "userAgentSettings" : {
-        "enabled" : false
-      },
-      "autoCert" : {
-        "enabled" : false,
-        "replyNicely" : false,
-        "caRef" : null,
-        "allowed" : [ ],
-        "notAllowed" : [ ]
-      },
-      "tlsSettings" : {
-        "defaultDomain" : null,
-        "randomIfNotFound" : false,
-        "includeJdkCaServer" : true,
-        "includeJdkCaClient" : true,
-        "trustedCAsServer" : [ ]
-      },
-      "plugins" : {
-        "enabled" : false,
-        "refs" : [ ],
-        "config" : { },
-        "excluded" : [ ]
-      },
-      "metadata" : { }
-    },
-    "admins" : [ ],
-    "simpleAdmins" : [ {
-      "_loc" : {
-        "tenant" : "default",
-        "teams" : [ "default" ]
-      },
-      "username" : "admin@otoroshi.io",
-      "password" : "$2a$10$iQRkqjKTW.5XH8ugQrnMDeUstx4KqmIeQ58dHHdW2Dv1FkyyAs4C.",
-      "label" : "Otoroshi Admin",
-      "createdAt" : 1634651307724,
-      "type" : "SIMPLE",
-      "metadata" : { },
-      "tags" : [ ],
-      "rights" : [ {
-        "tenant" : "*:rw",
-        "teams" : [ "*:rw" ]
-      } ]
-    } ],
-    "serviceGroups" : [ {
-      "_loc" : {
-        "tenant" : "default",
-        "teams" : [ "default" ]
-      },
-      "id" : "admin-api-group",
-      "name" : "Otoroshi Admin Api group",
-      "description" : "No description",
-      "tags" : [ ],
-      "metadata" : { }
-    }, {
-      "_loc" : {
-        "tenant" : "default",
-        "teams" : [ "default" ]
-      },
-      "id" : "default",
-      "name" : "default-group",
-      "description" : "The default service group",
-      "tags" : [ ],
-      "metadata" : { }
-    } ],
-    "apiKeys" : [ {
-      "_loc" : {
-        "tenant" : "default",
-        "teams" : [ "default" ]
-      },
-      "clientId" : "admin-api-apikey-id",
-      "clientSecret" : "admin-api-apikey-secret",
-      "clientName" : "Otoroshi Backoffice ApiKey",
-      "description" : "The apikey use by the Otoroshi UI",
-      "authorizedGroup" : "admin-api-group",
-      "authorizedEntities" : [ "group_admin-api-group" ],
-      "enabled" : true,
-      "readOnly" : false,
-      "allowClientIdOnly" : false,
-      "throttlingQuota" : 10000,
-      "dailyQuota" : 10000000,
-      "monthlyQuota" : 10000000,
-      "constrainedServicesOnly" : false,
-      "restrictions" : {
-        "enabled" : false,
-        "allowLast" : true,
-        "allowed" : [ ],
-        "forbidden" : [ ],
-        "notFound" : [ ]
-      },
-      "rotation" : {
-        "enabled" : false,
-        "rotationEvery" : 744,
-        "gracePeriod" : 168,
-        "nextSecret" : null
-      },
-      "validUntil" : null,
-      "tags" : [ ],
-      "metadata" : { }
-    } ],
-    "serviceDescriptors" : [ {
-      "_loc" : {
-        "tenant" : "default",
-        "teams" : [ "default" ]
-      },
-      "id" : "admin-api-service",
-      "groupId" : "admin-api-group",
-      "groups" : [ "admin-api-group" ],
-      "name" : "otoroshi-admin-api",
-      "description" : "",
-      "env" : "prod",
-      "domain" : "oto.tools",
-      "subdomain" : "otoroshi-api",
-      "targetsLoadBalancing" : {
-        "type" : "RoundRobin"
-      },
-      "targets" : [ {
-        "host" : "127.0.0.1:8080",
-        "scheme" : "http",
-        "weight" : 1,
-        "mtlsConfig" : {
-          "certs" : [ ],
-          "trustedCerts" : [ ],
-          "mtls" : false,
-          "loose" : false,
-          "trustAll" : false
-        },
-        "tags" : [ ],
-        "metadata" : { },
-        "protocol" : "HTTP/1.1",
-        "predicate" : {
-          "type" : "AlwaysMatch"
-        },
-        "ipAddress" : null
-      } ],
-      "root" : "/",
-      "matchingRoot" : null,
-      "stripPath" : true,
-      "localHost" : "127.0.0.1:8080",
-      "localScheme" : "http",
-      "redirectToLocal" : false,
-      "enabled" : true,
-      "userFacing" : false,
-      "privateApp" : false,
-      "forceHttps" : false,
-      "logAnalyticsOnServer" : false,
-      "useAkkaHttpClient" : true,
-      "useNewWSClient" : false,
-      "tcpUdpTunneling" : false,
-      "detectApiKeySooner" : false,
-      "maintenanceMode" : false,
-      "buildMode" : false,
-      "strictlyPrivate" : false,
-      "enforceSecureCommunication" : true,
-      "sendInfoToken" : true,
-      "sendStateChallenge" : true,
-      "sendOtoroshiHeadersBack" : true,
-      "readOnly" : false,
-      "xForwardedHeaders" : false,
-      "overrideHost" : true,
-      "allowHttp10" : true,
-      "letsEncrypt" : false,
-      "secComHeaders" : {
-        "claimRequestName" : null,
-        "stateRequestName" : null,
-        "stateResponseName" : null
-      },
-      "secComTtl" : 30000,
-      "secComVersion" : 1,
-      "secComInfoTokenVersion" : "Legacy",
-      "secComExcludedPatterns" : [ ],
-      "securityExcludedPatterns" : [ ],
-      "publicPatterns" : [ "/health", "/metrics" ],
-      "privatePatterns" : [ ],
-      "additionalHeaders" : {
-        "Host" : "otoroshi-admin-internal-api.oto.tools"
-      },
-      "additionalHeadersOut" : { },
-      "missingOnlyHeadersIn" : { },
-      "missingOnlyHeadersOut" : { },
-      "removeHeadersIn" : [ ],
-      "removeHeadersOut" : [ ],
-      "headersVerification" : { },
-      "matchingHeaders" : { },
-      "ipFiltering" : {
-        "whitelist" : [ ],
-        "blacklist" : [ ]
-      },
-      "api" : {
-        "exposeApi" : false
-      },
-      "healthCheck" : {
-        "enabled" : false,
-        "url" : "/"
-      },
-      "clientConfig" : {
-        "useCircuitBreaker" : true,
-        "retries" : 1,
-        "maxErrors" : 20,
-        "retryInitialDelay" : 50,
-        "backoffFactor" : 2,
-        "callTimeout" : 30000,
-        "callAndStreamTimeout" : 120000,
-        "connectionTimeout" : 10000,
-        "idleTimeout" : 60000,
-        "globalTimeout" : 30000,
-        "sampleInterval" : 2000,
-        "proxy" : { },
-        "customTimeouts" : [ ],
-        "cacheConnectionSettings" : {
-          "enabled" : false,
-          "queueSize" : 2048
-        }
-      },
-      "canary" : {
-        "enabled" : false,
-        "traffic" : 0.2,
-        "targets" : [ ],
-        "root" : "/"
-      },
-      "gzip" : {
-        "enabled" : false,
-        "excludedPatterns" : [ ],
-        "whiteList" : [ "text/*", "application/javascript", "application/json" ],
-        "blackList" : [ ],
-        "bufferSize" : 8192,
-        "chunkedThreshold" : 102400,
-        "compressionLevel" : 5
-      },
-      "metadata" : { },
-      "tags" : [ ],
-      "chaosConfig" : {
-        "enabled" : false,
-        "largeRequestFaultConfig" : null,
-        "largeResponseFaultConfig" : null,
-        "latencyInjectionFaultConfig" : null,
-        "badResponsesFaultConfig" : null
-      },
-      "jwtVerifier" : {
-        "type" : "ref",
-        "ids" : [ ],
-        "id" : null,
-        "enabled" : false,
-        "excludedPatterns" : [ ]
-      },
-      "secComSettings" : {
-        "type" : "HSAlgoSettings",
-        "size" : 512,
-        "secret" : "secret",
-        "base64" : false
-      },
-      "secComUseSameAlgo" : true,
-      "secComAlgoChallengeOtoToBack" : {
-        "type" : "HSAlgoSettings",
-        "size" : 512,
-        "secret" : "secret",
-        "base64" : false
-      },
-      "secComAlgoChallengeBackToOto" : {
-        "type" : "HSAlgoSettings",
-        "size" : 512,
-        "secret" : "secret",
-        "base64" : false
-      },
-      "secComAlgoInfoToken" : {
-        "type" : "HSAlgoSettings",
-        "size" : 512,
-        "secret" : "secret",
-        "base64" : false
-      },
-      "cors" : {
-        "enabled" : false,
-        "allowOrigin" : "*",
-        "exposeHeaders" : [ ],
-        "allowHeaders" : [ ],
-        "allowMethods" : [ ],
-        "excludedPatterns" : [ ],
-        "maxAge" : null,
-        "allowCredentials" : true
-      },
-      "redirection" : {
-        "enabled" : false,
-        "code" : 303,
-        "to" : "https://www.otoroshi.io"
-      },
-      "authConfigRef" : null,
-      "clientValidatorRef" : null,
-      "transformerRef" : null,
-      "transformerRefs" : [ ],
-      "transformerConfig" : { },
-      "apiKeyConstraints" : {
-        "basicAuth" : {
-          "enabled" : true,
-          "headerName" : null,
-          "queryName" : null
-        },
-        "customHeadersAuth" : {
-          "enabled" : true,
-          "clientIdHeaderName" : null,
-          "clientSecretHeaderName" : null
-        },
-        "clientIdAuth" : {
-          "enabled" : true,
-          "headerName" : null,
-          "queryName" : null
-        },
-        "jwtAuth" : {
-          "enabled" : true,
-          "secretSigned" : true,
-          "keyPairSigned" : true,
-          "includeRequestAttributes" : false,
-          "maxJwtLifespanSecs" : null,
-          "headerName" : null,
-          "queryName" : null,
-          "cookieName" : null
-        },
-        "routing" : {
-          "noneTagIn" : [ ],
-          "oneTagIn" : [ ],
-          "allTagsIn" : [ ],
-          "noneMetaIn" : { },
-          "oneMetaIn" : { },
-          "allMetaIn" : { },
-          "noneMetaKeysIn" : [ ],
-          "oneMetaKeyIn" : [ ],
-          "allMetaKeysIn" : [ ]
-        }
-      },
-      "restrictions" : {
-        "enabled" : false,
-        "allowLast" : true,
-        "allowed" : [ ],
-        "forbidden" : [ ],
-        "notFound" : [ ]
-      },
-      "accessValidator" : {
-        "enabled" : false,
-        "refs" : [ ],
-        "config" : { },
-        "excludedPatterns" : [ ]
-      },
-      "preRouting" : {
-        "enabled" : false,
-        "refs" : [ ],
-        "config" : { },
-        "excludedPatterns" : [ ]
-      },
-      "plugins" : {
-        "enabled" : false,
-        "refs" : [ ],
-        "config" : { },
-        "excluded" : [ ]
-      },
-      "hosts" : [ "otoroshi-api.oto.tools" ],
-      "paths" : [ ],
-      "handleLegacyDomain" : true,
-      "issueCert" : false,
-      "issueCertCA" : null
-    } ],
-    "errorTemplates" : [ ],
-    "jwtVerifiers" : [ ],
-    "authConfigs" : [ ],
-    "certificates" : [],
-    "clientValidators" : [ ],
-    "scripts" : [ ],
-    "tcpServices" : [ ],
-    "dataExporters" : [ ],
-    "tenants" : [ {
-      "id" : "default",
-      "name" : "Default organization",
-      "description" : "The default organization",
-      "metadata" : { },
-      "tags" : [ ]
-    } ],
-    "teams" : [ {
-      "id" : "default",
-      "tenant" : "default",
-      "name" : "Default Team",
-      "description" : "The default Team of the default organization",
-      "metadata" : { },
-      "tags" : [ ]
-    } ]
-  }' \
-  'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \
-  -u admin-api-apikey-id:admin-api-apikey-secret 
-
-

This should output :

-
{ "done":true }
-
-
-

Note : be very carefully with this POST command. If you send a wrong JSON, you risk breaking your instance.

-
-

The second way is to send the same configuration but from a file. You can pass two kind of file : a json file or a ndjson file. Both files are available as export methods on the danger zone.

-
# the curl is run from a folder containing the initial-state.json file 
-curl -X POST \
-  -H "Content-Type: application/json" \
-  -d @./initial-state.json \
-  'http://otoroshi-api.oto.tools:8080/api/otoroshi.json' \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-

This should output :

-
{ "done":true }
-
-
-

Note: To send a ndjson file, you have to set the Content-Type header at application/x-ndjson

-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/index.html b/docs/manual/how-to-s/index.html deleted file mode 100644 index 4d505ad57a..0000000000 --- a/docs/manual/how-to-s/index.html +++ /dev/null @@ -1,367 +0,0 @@ - - - - -How tos · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- - - -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/resources-loader.html b/docs/manual/how-to-s/resources-loader.html deleted file mode 100644 index 29ca5f53fb..0000000000 --- a/docs/manual/how-to-s/resources-loader.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - -The resources loader · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

The resources loader

-

The resources loader is a tool to create an Otoroshi resource from a raw content. This content can be found on each Otoroshi resources pages (services descriptors, apikeys, certificates, etc …). To get the content of a resource as file, you can use the two export buttons, one to export as JSON format and the other as YAML format.

-

Once exported, the content of the resource can be import with the resource loader. You can import single or multiples resources on one time, as JSON and YAML format.

-

The resource loader is available on this route bo/dashboard/resources-loader.

-

On this page, you can paste the content of your resources and click on Load resources.

-

For each detected resource, the loader will display :

-
    -
  • a resource name corresponding to the field name
  • -
  • a resource type corresponding to the type of created resource (ServiceDescriptor, ApiKey, Certificate, etc)
  • -
  • a toggle to choose if you want to include the element for the creation step
  • -
  • the updated status by the creation process
  • -
-

Once you have selected the resources to create, you can Import selected resources.

-

Once generated, all status will be updated. If all is working, the status will be equals to done.

-

If you want to get back to the initial page, you can use the restart button.

- -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-an-app-with-jwt-verifiers.html b/docs/manual/how-to-s/secure-an-app-with-jwt-verifiers.html deleted file mode 100644 index 6e03c6a00c..0000000000 --- a/docs/manual/how-to-s/secure-an-app-with-jwt-verifiers.html +++ /dev/null @@ -1,462 +0,0 @@ - - - - -Secure an api with jwt verifiers · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an api with jwt verifiers

-

A Jwt verifier is the guard which check the signature of tokens present in incoming requests on a service. It can be a simple verifier, a tokens generator, or extend to be a verifier and a tokens generator.

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Your first jwt verifier : a verifier of tokens

-

Let’s start navigating the page of verifier creation. By default, the type of jwt verifier is a Verify JWT token.

-

Create the following verifier :

-
    -
  • Set simple-jwt-verifier as Name
  • -
  • Set My simple jwt verifier as Description
  • -
  • We expect in entry a token in a specific header. Set Authorization as Header name
  • -
  • Select Hmac + SHA as Algo (for this example, we expect tokens with a symetric signature)
  • -
  • Set otoroshi as Hmac secret
  • -
  • Remove the default field in Verify token fields array
  • -
  • Create your verifier when clicking on Create and stay on this Jwt verifier button.
  • -
-

Once created, navigate to the simple service (created in Before you start section) and jump to the JWT tokens verification section.

-

In the verifiers list, choose the simple-jwt-verifier and enabled the section.

-

Save your service and try to call the service.

-
curl -X GET 'http://myservice.oto.tools:8080/' --include
-
-

This should output :

-
{
-    "Otoroshi-Error": "error.expected.token.not.found"
-}
-
-

A simple way to generate a token is to use jwt.io. Once navigate, define HS512 as alg in header section, and insert otoroshi as verify signature secret.

-

Once created, copy-paste the token from jwt.io to the Authorization header and call our service.

-
# replace xxxx by the generated token
-curl -X GET \
-  -H "Authorization: xxxx" \
-  'http://myservice.oto.tools:8080'
-
-

This should output a json with authorization in headers field. His value is exactly the same as the passed token.

-
{
-  "method": "GET",
-  "path": "/",
-  "headers": {
-    "host": "mirror.otoroshi.io",
-    "authorization": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.ipDFgkww51mSaSg_199BMRj4gK20LGz_czozu3u8rCFFO1X20MwcabSqEzUc0q4qQ4rjTxjoR4HeUDVcw8BxoQ",
-    ...
-  }
-}
-
-

Verify and generate a new token

-

An other feature is to verify the entry token and generate a new token, with a different signature and news claims.

-

Let’s start by extending the previous verifier.

-
    -
  1. Jump to the Verif Strategy field and select Verify and re-sign JWT token.
  2. -
  3. Edit the name with jwt-verify-and-resign
  4. -
  5. Remove the default field in Verify token fields array
  6. -
  7. Change the second Hmac secret in Re-sign settings section with otoroshi-internal-secret
  8. -
  9. Save your verifier.
  10. -
-
-

Note : the name of the verifier doesn’t impact the identifier. So you can save the changes of your verifier without modifying the identifier used in your call.

-
-
# replace xxxx by the generated token
-curl -X GET \
-  -H "Authorization: xxxx" \
-  'http://myservice.oto.tools:8080'
-
-

This should output a json with authorization in headers field. This time, the value are different and you can check his signature on jwt.io (the expected secret of the generated token is otoroshi-internal-secret)

- -

Verify, transform and generate a new token

-

The most advanced verifier is able to do the same as the previous ones, with the ability to configure the token generation (claims, output header name).

-

Let’s start by extending the previous verifier.

-
    -
  1. -

    Jump to the Verif Strategy field and select Verify, transform and re-sign JWT token.

  2. -
  3. -

    Edit the name with jwt-verify-transform-and-resign

  4. -
  5. Remove the default field in Verify token fields array
  6. -
  7. Change the second Hmac secret in Re-sign settings section with otoroshi-internal-secret
  8. -
  9. Set Internal-Authorization as Header name
  10. -
  11. Set key on first field of Rename token fields and from-otoroshi-verifier on second field
  12. -
  13. Set generated-key and generated-value as Set token fields
  14. -
  15. Add generated_at and ${date} as second field of Set token fields (Otoroshi supports an expression language)
  16. -
  17. Save your verifier and try to call your service again.
  18. -
-

This should output a json with authorization in headers field and our generate token in Internal-Authorization. Once paste in jwt.io, you should have :

- -

You can see, in the payload of your token, the two claims from-otoroshi-verifier and generated-key added during the generation of the token by the JWT verifier.

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-app-with-auth0.html b/docs/manual/how-to-s/secure-app-with-auth0.html deleted file mode 100644 index b60f0fd6fb..0000000000 --- a/docs/manual/how-to-s/secure-app-with-auth0.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - -Secure an app with Auth0 · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an app with Auth0

-

Download Otoroshi

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Configure an Auth0 client

-

The first step of this tutorial is to setup an Auth0 application with the information of the instance of our Otoroshi.

-

Navigate to https://manage.auth0.com (create an account if it’s not already done).

-

Let’s create an application when clicking on the Applications button on the sidebar. Then click on the Create application button on the top right.

-
    -
  1. Choose Regular Web Applications as Application type
  2. -
  3. Then set for example otoroshi-client as Name, and confirm the creation
  4. -
  5. Jump to the Settings tab
  6. -
  7. Scroll to the Application URLs section and add the following url as Allowed Callback URLs : http://otoroshi.oto.tools:8080/backoffice/auth0/callback
  8. -
  9. Set https://otoroshi.oto.tools:8080/ as Allowed Logout URLs
  10. -
  11. Set https://otoroshi.oto.tools:8080 as Allowed Web Origins
  12. -
  13. Save changes at the bottom of the page.
  14. -
-

Once done, we have a full setup, with a client ID and secret at the top of the page, which authorizes our Otoroshi and redirects the user to the callback url when they log into Auth0.

-

Create an Auth0 provider module

-

Let’s back to Otoroshi to create an authentication module with OAuth2 / OIDC provider as type.

-
    -
  1. Go ahead, and navigate to http://otoroshi.oto.tools:8080
  2. -
  3. Click on the cog icon on the top right
  4. -
  5. Then Authentication configs button
  6. -
  7. And add a new configuration when clicking on the Add item button
  8. -
  9. Select the OAuth provider in the type selector field
  10. -
  11. Then click on Get from OIDC config and paste https://<tenant-name>.<region>.auth0.com/.well-known/openid-configuration. Replace the tenant name by the name of your tenant (displayed on the left top of auth0 page), and the region of the tenant (eu in my case).
  12. -
-

Once done, set the Client ID and the Client secret from your Auth0 application. End the configuration with http://otoroshi.oto.tools:8080/backoffice/auth0/callback as Callback URL.

-

At the bottom of the page, disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs).

-

Connect to Otoroshi with Auth0 authentication

-

To secure Otoroshi with your Auth0 configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.

-
    -
  1. Navigate to the danger zone (when clicking on the cog on the top right and selecting Danger zone)
  2. -
  3. Scroll to the BackOffice auth. settings
  4. -
  5. Select your last Authentication configuration (created in the previous section)
  6. -
  7. Save the global configuration with the button on the top right
  8. -
-

Testing your configuration

-
    -
  1. Disconnect from your instance
  2. -
  3. Then click on the Login using third-party button (or navigate to http://otoroshi.oto.tools:8080)
  4. -
  5. Click on Login using Third-party button
  6. -
  7. If all is configured, Otoroshi will redirect you to the auth0 server login page
  8. -
  9. Set your account credentials
  10. -
  11. Good works! You’re connected to Otoroshi with an Auth0 module.
  12. -
-

Secure an app with Auth0 authentication

-

With the previous configuration, you can secure any of Otoroshi services with it.

-

The first step is to apply a little change on the previous configuration.

-
    -
  1. Navigate to http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs.
  2. -
  3. Create a new Authentication module configuration with the same values.
  4. -
  5. Replace the Callback URL field to http://privateapps.oto.tools:8080/privateapps/generic/callback (we changed this value because the redirection of a connected user by a third-party server is covered by another route by Otoroshi).
  6. -
  7. Disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)
  8. -
-
-

Note : an Otoroshi service is called a private app when it is protected by an Authentication module.

-
-

We can set the Authentication module on the service.

-
    -
  1. Navigate to any created service
  2. -
  3. Scroll to Authentication section
  4. -
  5. Enable Enforce user authentication
  6. -
  7. Select your Authentication config inside the list
  8. -
  9. Enable Strict mode
  10. -
  11. Don’t forget to save your configuration.
  12. -
  13. Now you can try to call your defined service and see the Auth0 login page appears.
  14. -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-app-with-keycloak.html b/docs/manual/how-to-s/secure-app-with-keycloak.html deleted file mode 100644 index b9fd8255e6..0000000000 --- a/docs/manual/how-to-s/secure-app-with-keycloak.html +++ /dev/null @@ -1,621 +0,0 @@ - - - - -Secure an app with Keycloak · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an app with Keycloak

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Running a keycloak instance with docker

-
docker run \
-  -p 8080:8080 \
-  -e KEYCLOAK_USER=admin \
-  -e KEYCLOAK_PASSWORD=admin \
-  --name keycloak-server \
-  --detach jboss/keycloak:15.0.1
-
-

This should download the image of keycloak (if you haven’t already it) and display the digest of the created container. This command mapped TCP port 8080 in the container to port 8080 of your laptop and created a server with admin/admin as admin credentials.

-

Once started, you can open a browser on http://localhost:8080 and click on Administration Console. Log to your instance with admin/admin as credentials.

-

The first step is to create a Keycloak client, an entity that can request Keycloak to authenticate a user. Click on the clients button on the sidebar, and then on Create button at the top right of the view.

-

Fill the client form with the following values.

-
    -
  • Client ID: keycloak-otoroshi-backoffice
  • -
  • Client Protocol: openid-connect
  • -
  • Root URL: http://otoroshi.oto.tools:8080/
  • -
-

Validate the creation of the client by clicking on the Save button.

-

The next step is to change the Access Type used by default. Jump to the Access Type field and select confidential. The confidential configuration force the client application to send at Keycloak a client ID and a client Secret. Scroll to the bottom of the page and save the configuration.

-

Now scroll to the top of your page. Just at the right of the Settings tab, a new tab appeared : the Credentials page. Click on this tab, and make sure that Client Id and Secret is selected as Client Authenticator and copy the generated Secret to the next part.

-

Create a Keycloak provider module

-
    -
  1. Go ahead, and navigate to http://otoroshi.oto.tools:8080
  2. -
  3. Click on the cog icon on the top right
  4. -
  5. Then Authentication configs button
  6. -
  7. And add a new configuration when clicking on the Add item button
  8. -
  9. Select the OAuth2 / OIDC provider in the type selector field
  10. -
  11. Set a basic name and description
  12. -
-

A simple way to import a Keycloak client is to give the URL of the OpenID Connect Otoroshi. By default, keycloak used the next URL : http://localhost:8080/auth/realms/master/.well-known/openid-configuration.

-

Click on the Get from OIDC config button and paste the previous link. Once it’s done, scroll to the URLs section. All URLs has been fill with the values picked from the JSON object returns by the previous URL.

-

The only fields to change are :

-
    -
  • Client ID: keycloak-otoroshi-backoffice
  • -
  • Client Secret: Paste the secret from the Credentials Keycloak page. In my case, it’s something like 90c9bf0b-2c0c-4eb0-aa02-72195beb9da7
  • -
  • Callback URL: http://otoroshi.oto.tools:8080/backoffice/auth0/callback
  • -
-

At the bottom of the page, disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs). Nothing else to change, just save the configuration.

-

Connect to Otoroshi with Keycloak authentication

-

To secure Otoroshi with your Keycloak configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.

-
    -
  1. Navigate to the danger zone (when clicking on the cog on the top right and selecting Danger zone)
  2. -
  3. Scroll to the BackOffice auth. settings
  4. -
  5. Select your last Authentication configuration (created in the previous section)
  6. -
  7. Save the global configuration with the button on the top right
  8. -
-

Testing your configuration

-
    -
  1. Disconnect from your instance
  2. -
  3. Then click on the Login using third-party button (or navigate to http://otoroshi.oto.tools:8080)
  4. -
  5. Click on Login using Third-party button
  6. -
  7. If all is configured, Otoroshi will redirect you to the keycloak login page
  8. -
  9. Set admin/admin as user and trust the user by clicking on yes button.
  10. -
  11. Good work! You’re connected to Otoroshi with an Keycloak module.
  12. -
-
-

A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.

-
-

Visualize an admin user session or a private user session

-

Each user, wheter connected user to the Otoroshi UI or at a private Otoroshi app, has an own session. As an administrator of Otoroshi, you can visualize via Otoroshi the list of the connected users and their profile.

-

Let’s start by navigating to the Admin users sessions page (just here or when clicking on the cog, and on the Admins sessions button at the bottom of the list).

-

This page gives a complete view of the connected admins. For each admin, you have his connection date and his expiration date. You can also check the Profile and the Rights of the connected users.

-

If we check the profile and the rights of the previously logged user (from Keycloak in the previous part) we can retrieve the following information :

-
{
-  "sub": "4c8cd101-ca28-4611-80b9-efa504ac51fd",
-  "upn": "admin",
-  "email_verified": false,
-  "address": {},
-  "groups": [
-    "create-realm",
-    "default-roles-master",
-    "offline_access",
-    "admin",
-    "uma_authorization"
-  ],
-  "preferred_username": "admin"
-}
-
-

and his default rights

-
[
-  {
-    "tenant": "default:rw",
-    "teams": [
-      "default:rw"
-    ]
-  }
-]
-
-

We haven’t create any specific groups in Keycloak or specify rights in Otoroshi for him. In this case, the use received the default Otoroshi rights at his connection. The user can navigate on the default Organization and Teams (which are two resources created by Otoroshi at the boot) and have the full access on its (r: Read, w: Write, *: read/write).

-

In the same way, you’ll find all users connected to a private Otoroshi app when navigate on the Private App View or using the cog at the top of the page.

-

Configure the Keycloak module to force logged in users to be an Otoroshi admin with full access

-

Go back to the Keycloak module in Authentication configs view. Turn on the Supers admin only button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.

-

Once connected, click on the cog button, and check that you have access to the full features of Otoroshi (like Admin user sessions). Now, your rights should be :

-
[
-  {
-    "tenant": "*:rw",
-    "teams": [
-      "*:rw"
-    ]
-  }
-]
-
-

Merge Id token content on user profile

-

Go back to the Keycloak module in Authentication configs view. Turn on the Read profile from token button and save your configuration. Try again the connection to Otoroshi using Keycloak third-party server.

-

Once connected, your profile should be contains all Keycloak id token :

-
{
-    "exp": 1634286674,
-    "iat": 1634286614,
-    "auth_time": 1634286614,
-    "jti": "eb368578-e886-4caa-a51b-c1d04973c80e",
-    "iss": "http://localhost:8080/auth/realms/master",
-    "aud": [
-        "master-realm",
-        "account"
-    ],
-    "sub": "4c8cd101-ca28-4611-80b9-efa504ac51fd",
-    "typ": "Bearer",
-    "azp": "keycloak-otoroshi-backoffice",
-    "session_state": "e44fe471-aa3b-477d-b792-4f7b4caea220",
-    "acr": "1",
-    "allowed-origins": [
-        "http://otoroshi.oto.tools:8080"
-    ],
-    "realm_access": {
-        "roles": [
-        "create-realm",
-        "default-roles-master",
-        "offline_access",
-        "admin",
-        "uma_authorization"
-        ]
-    },
-    "resource_access": {
-        "master-realm": {
-        "roles": [
-            "view-identity-providers",
-            "view-realm",
-            "manage-identity-providers",
-            "impersonation",
-            "create-client",
-            "manage-users",
-            "query-realms",
-            "view-authorization",
-            "query-clients",
-            "query-users",
-            "manage-events",
-            "manage-realm",
-            "view-events",
-            "view-users",
-            "view-clients",
-            "manage-authorization",
-            "manage-clients",
-            "query-groups"
-        ]
-        },
-        "account": {
-        "roles": [
-            "manage-account",
-            "manage-account-links",
-            "view-profile"
-        ]
-        }
-    }
-    ...
-}
-
-

Manage the Otoroshi user rights from keycloak

-

One powerful feature supports by Otoroshi, is to use the Keycloak groups attributes to set a list of rights for a Otoroshi user.

-

In the Keycloak module, you have a field, named Otoroshi rights field name with otoroshi_rights as default value. This field is used by Otoroshi to retrieve information from the Id token groups.

-

Let’s create a group in Keycloak, and set our default Admin user inside. In Keycloak admin console :

-
    -
  1. Navigate to the groups view, using the keycloak sidebar
  2. -
  3. Create a new group with my-group as Name
  4. -
  5. -

    Then, on the Attributes tab, create an attribute with otoroshi_rights as Key and the following json array as Value

    -
    [
    -{
    -    "tenant": "*:rw",
    -    "teams": [
    -        "*:rw",
    -        "my-future-team:rw"
    -    ]
    -}
    -]
    -
  6. -
-

With this configuration, the user have a full access on all Otoroshi resources (my-future-team is not created in Otoroshi but it’s not a problem, Otoroshi can handle it and use this rights only when the team will be present)

-

Click on the Add button and save the group. The last step is to assign our user to this group. Jump to Users view using the sidebar, click on View all users, edit the user and his group membership using the Groups tab (use join button the assign user in my-group).

-

The next step is to add a mapper in the Keycloak client. By default, Keycloak doesn’t expose any users information (like group membership or users attribute). We need to ask to Keycloak to expose the user attribute otoroshi_rights set previously on group.

-

Navigate to the Keycloak-otoroshi-backoffice client, and jump to Mappers tab. Create a new mapper with the following values:

-
    -
  • Name: otoroshi_rights
  • -
  • Mapper Type: User Attribute
  • -
  • User Attribute: otoroshi_rights
  • -
  • Token Claim Name: otoroshi_rights
  • -
  • Claim JSON Type: JSON
  • -
  • Multivalued:
  • -
  • Aggregate attribute values:
  • -
-

Go back to the Authentication Keycloak module inside Otoroshi UI, and turn off Super admins only. Save the configuration.

-

Once done, try again the connection to Otoroshi using Keycloak third-party server. Now, your rights should be :

-
[
-  {
-    "tenant": "*:rw",
-    "teams": [
-      "*:rw",
-      "my-future-team:rw"
-    ]
-  }
-]
-
-

Secure an app with Keycloak authentication

-

The only change to apply on the previous authentication module is on the callback URL. When you want secure a Otoroshi service, and transform it on Private App, you need to set the Callback URL at http://privateapps.oto.tools:8080/privateapps/generic/callback. This configuration will redirect users to the backend service after they have successfully logged in.

-
    -
  1. Go back to the authentication module
  2. -
  3. Jump to the Callback URL field
  4. -
  5. Paste this value http://privateapps.oto.tools:8080/privateapps/generic/callback
  6. -
  7. Save your configuration
  8. -
  9. Navigate to http://myservice.oto.tools:8080.
  10. -
  11. You should redirect to the keycloak login page.
  12. -
  13. Once logged in, you can check the content of the private app session created.
  14. -
-

The rights should be :

-
[
-  {
-    "tenant": "*:rw",
-    "teams": [
-      "*:rw",
-      "my-future-team:rw"
-    ]
-  }
-]
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-app-with-ldap.html b/docs/manual/how-to-s/secure-app-with-ldap.html deleted file mode 100644 index 987738afe5..0000000000 --- a/docs/manual/how-to-s/secure-app-with-ldap.html +++ /dev/null @@ -1,612 +0,0 @@ - - - - -Secure an app and/or your Otoroshi UI with LDAP · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an app and/or your Otoroshi UI with LDAP

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Running an simple OpenLDAP server

-

Run OpenLDAP docker image :

-
docker run \
-  -p 389:389 \
-  -p 636:636  \
-  --env LDAP_ORGANISATION="Otoroshi company" \
-  --env LDAP_DOMAIN="otoroshi.tools" \
-  --env LDAP_ADMIN_PASSWORD="otoroshi" \
-  --env LDAP_READONLY_USER="false" \
-  --env LDAP_TLS"false" \
-  --env LDAP_TLS_ENFORCE"false" \
-  --name my-openldap-container \
-  --detach osixia/openldap:1.5.0
-
-

Let’s make the first search in our LDAP container :

-
docker exec my-openldap-container ldapsearch -x -H ldap://localhost -b dc=otoroshi,dc=tools -D "cn=admin,dc=otoroshi,dc=tools" -w otoroshi
-
-

This should output :

-
# extended LDIF
- ...
-# otoroshi.tools
-dn: dc=otoroshi,dc=tools
-objectClass: top
-objectClass: dcObject
-objectClass: organization
-o: Otoroshi company
-dc: otoroshi
-
-# search result
-search: 2
-result: 0 Success
-...
-
-

Now you can seed the open LDAP server with a few users.

-

Join your LDAP container.

-
docker exec -it my-openldap-container "/bin/bash"
-
-

The command ldapadd needs of a file to run.

-

Launch this command to create a bootstrap.ldif with one organization, one singers group with Johnny user and a last group with Einstein as scientist.

-
echo -e "
-dn: ou=People,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: organizationalUnit
-ou: People
-
-dn: ou=Role,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: organizationalUnit
-ou: Role
-
-dn: uid=johnny,ou=People,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: person
-objectclass: organizationalPerson
-objectclass: inetOrgPerson
-uid: johnny
-cn: Johnny
-sn: Brown
-mail: johnny@otoroshi.tools
-postalCode: 88442
-userPassword: password
-
-dn: uid=einstein,ou=People,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: person
-objectclass: organizationalPerson
-objectclass: inetOrgPerson
-uid: einstein
-cn: Einstein
-sn: Wilson
-mail: einstein@otoroshi.tools
-postalCode: 88443
-userPassword: password
-
-dn: cn=singers,ou=Role,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: groupOfNames
-cn: singers
-member: uid=johnny,ou=People,dc=otoroshi,dc=tools
-
-dn: cn=scientists,ou=Role,dc=otoroshi,dc=tools
-objectclass: top
-objectclass: groupOfNames
-cn: scientists
-member: uid=einstein,ou=People,dc=otoroshi,dc=tools
-" > bootstrap.ldif
-
-ldapadd -x -w otoroshi -D "cn=admin,dc=otoroshi,dc=tools" -f bootstrap.ldif -v
-
-

Create an Authentication configuration

-
    -
  • Go ahead, and navigate to http://otoroshi.oto.tools:8080
  • -
  • Click on the cog icon on the top right
  • -
  • Then Authentication configs button
  • -
  • And add a new configuration when clicking on the Add item button
  • -
  • Select the Ldap auth. provider in the type selector field
  • -
  • Set a basic name and description
  • -
  • Then set ldap://localhost:389 as LDAP Server URLand dc=otoroshi,dc=tools as Search Base
  • -
  • Create a group filter (in the next part, we’ll change this filter to spread users in different groups with given rights) with -
      -
    • objectClass=groupOfNames as Group filter
    • -
    • All as Tenant
    • -
    • All as Team
    • -
    • Read/Write as Rights
    • -
    -
  • -
  • Set the search filter as (uid=${username})
  • -
  • Set cn=admin,dc=otoroshi,dc=tools as Admin username
  • -
  • Set otoroshi as Admin password
  • -
  • At the bottom of the page, disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)
  • -
-

At this point, your configuration should be similar to :

- - -
-

Dont’ forget to save on the bottom page your configuration before to quit the page.

-
-
    -
  • -

    Test the connection when clicking on Test admin connection button. This should display a It works! message

  • -
  • -

    Finally, test the user connection button and set johnny/password or einstein/password as credentials. This should display a It works! message

  • -
-
-

Dont’ forget to save on the bottom page your configuration before to quit the page.

-
-

Connect to Otoroshi with LDAP authentication

-

To secure Otoroshi with your LDAP configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.

-
    -
  • Navigate to the danger zone (when clicking on the cog on the top right and selecting Danger zone)
  • -
  • Scroll to the BackOffice auth. settings
  • -
  • Select your last Authentication configuration (created in the previous section)
  • -
  • Save the global configuration with the button on the top right
  • -
-

Testing your configuration

- -
-

A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.

-
-

Secure an app with LDAP authentication

-

Once the configuration is done, you can secure any of Otoroshi services.

-
    -
  • Navigate to any created service
  • -
  • Jump to the URL Patterns section
  • -
  • Enable your service as Public UI
  • -
  • Then scroll to Authentication section
  • -
  • Enable Enforce user authentication
  • -
  • Select your Authentication config inside the list
  • -
  • Enable Strict mode
  • -
  • Don’t forget to save your configuration
  • -
- - -

Now you can try to call your defined service and see the login module appears.

-

Manage LDAP users rights on Otoroshi

-

For each LDAP groups, you can affect a list of rights :

-
    -
  • on an Organization : only resources of an organization
  • -
  • on a Team : only resources belonging to this team
  • -
  • and a level of rights : Read, Write or Read/Write
  • -
-

Start by navigate to your authentication configuration (created in previous step).

-

Then, replace the values of the Mapping group filter field to match LDAP groups with Otoroshi rights.

- - -

With this configuration, Einstein is an administrator of Otoroshi with full rights (read / write) on all organizations.

-

Conversely, Johnny can’t see any configuration pages (like the danger zone) because he has only the read rights on Otoroshi.

-

You can easily test this behaviour by testing with both credentials.

-

Advanced usage of LDAP Authentication

-

In the previous section, we have define rights for each LDAP groups. But in some case, we want to have a finer granularity like set rights for a specific user. The last 4 fields of the authentication form cover this.

-

Let’s start by adding few properties for each connected users with Extra metadata.

-
// Add this configuration in extra metadata part
-{
-  "provider": "OpenLDAP"
-}
-
-

The next field Data override is merged with extra metadata when a user connects to a private app or to the UI (inside Otoroshi, private app is a service secure by any authentication module). The Email field name is configured to match with the mail field from LDAP user data.

-
{
-  "johnny@otoroshi.tools": {
-    "stage_name": "Jean-Philippe Smet"
-  }
-}
-
-

If you try to connect to an app with this configuration, the user result profile should be :

-
{
-  ...,
-  "metadata": {
-    "lastname": "Hallyday",
-    "stage_name": "Jean-Philippe Smet"
-  }
-}
-
-

Let’s try to increase the Johnny rights with the Additional rights group.

-

This field supports the creation of virtual groups. A virtual group is composed of a list of users and a list of rights for each teams/organizations.

-
// increase_johnny_rights is a virtual group which adds full access rights at johnny 
-{
-  "increase_johnny_rights": {
-    "rights": [
-      {
-        "tenant": "*:rw",
-        "teams": [
-          "*:rw"
-        ]
-      }
-    ],
-    "users": [
-      "johnny@otoroshi.tools"
-    ]
-  }
-}
-
-

The last field Rights override is useful when you want erase the rights of an user with only specific rights. This field is the last to be applied on the user rights.

-

To resume, when Johnny connects to Otoroshi, he receives the rights to only read the default Organization (from Mapping group filter), then he is promote to administrator role (from Additional rights group) and finally his rights are reset with the last field Rights override to the read rights.

-
{
-  "johnny@otoroshi.tools": [
-    {
-      "tenant": "*:r",
-      "teams": [
-        "*:r"
-      ]
-    }
-  ]
-}
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.html b/docs/manual/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.html deleted file mode 100644 index d00ae51c06..0000000000 --- a/docs/manual/how-to-s/secure-the-communication-between-a-backend-app-and-otoroshi.html +++ /dev/null @@ -1,391 +0,0 @@ - - - - -Secure the communication between a backend app and Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure the communication between a backend app and Otoroshi

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-
    -
  1. Navigate to http://otoroshi.oto.tools:8080/bo/services and create a new service
  2. -
  3. Jump to Service exposition settings and add http://myservice.oto.tools as Exposed domain
  4. -
  5. Jump to Service targets and add http://localhost:8081/ as Target 1
  6. -
  7. Jump to the URL Patterns section
  8. -
  9. Enable your service as Public UI
  10. -
  11. Don’t forget to save your service
  12. -
-

We need of a simple service which handle the exchange protocol. For this tutorial, we’ll use the following application, developed in NodeJS, which supports both versions of the exchange protocol.

-

Clone this repository and run the installation of the dependencies.

-
git clone 'git@github.com:MAIF/otoroshi.git' --depth=1
-cd ./otoroshi/demos/challenge
-npm install
-PORT=8081 node server.js
-
-

The last command should return :

-
challenge-verifier listening on http://0.0.0.0:8081
-
-

This project runs an express client with one middleware. The middleware handles each request, and check if the header State token header is present in headers. By default, the incoming expected header is Otoroshi-State by the application and Otoroshi-State-Resp header in the headers of the return request.

-

Try to call your service via http://myservice.oto.tools:8080/. This should return a successful response with all headers received by the backend app.

-

Now try to disable the middleware in the nodejs file by commenting the following line.

-
// app.use(OtoroshiMiddleware());
-
-

Try to call again your service. This time, Otoroshi breaks the return response from your backend service, and returns.

-
Downstream microservice does not seems to be secured. Cancelling request !
-
- -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-with-apikey.html b/docs/manual/how-to-s/secure-with-apikey.html deleted file mode 100644 index 7d212619be..0000000000 --- a/docs/manual/how-to-s/secure-with-apikey.html +++ /dev/null @@ -1,482 +0,0 @@ - - - - -Secure an api with api keys · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an api with api keys

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a simple service

-
    -
  1. Navigate to http://otoroshi.oto.tools:8080/bo/dashboard/services and click on the create new service button
  2. -
  3. Jump to Service exposition settings and add http://myservice.oto.tools as Exposed domain
  4. -
  5. Jump to Service targets and add https://mirror.otoroshi.io as Target 1
  6. -
  7. Jump to the URL Patterns section
  8. -
  9. Enable your service as Public UI
  10. -
  11. Open a new tab and navigate to http://myservice.oto.tools:8080
  12. -
-

With this configuration, all routes are public, wihtout any authentication needed.

-

Secure routes with api key

-

With the previous configuration, all routes are public. In our case, we want to secure all routes prefix with /api.

-

Let’s return to the URL Patterns section. Click on Make service a private api. This button automatically add /api as default in Private patterns array. (Note that the field supports regex like. In our case, /api.* covers all routes starting by /api).

-

Save your app and navigate to http://myservice.oto.tools:8080/api/test again. If the service is configured, you should have a Service Not found error, and a success call, in the case you navigate to any other routes which are not starting by /api/* like http://myservice.oto.tools:8080/test/bar

-

The expected error on the /api/test, throws by the URL Patterns, indicate to the client that an api key is required to access to this part of the backend service.

-

Generate an api key to request secure services

-

Navigate to http://otoroshi.oto.tools:8080/bo/dashboard/apikeys/add or when clicking on the Add apikey button on the sidebar.

-

The only required fields of an Otoroshi api key are :

-
    -
  • ApiKey id
  • -
  • ApiKey Secret
  • -
  • ApiKey Name
  • -
-

These fields are automatically generated by Otoroshi. However, you can override these values and indicate an additional description.

-

To simplify the rest of the tutorial, set the values:

-
    -
  • my-first-api-key-id as ApiKey Id
  • -
  • my-first-api-key-secret as ApiKey Secret
  • -
-

Click on Create and stay on this ApiKey button at the bottom of the page.

-

Now you created the key, it’s time to call our previous generated service with it.

-

Otoroshi supports two methods to achieve that. Once by passing Otoroshi api key in two headers : Otoroshi-Client-Id and Otoroshi-Client-Secret (these headers names can be override on each service). And the second by passing Otoroshi api key in the authentication Header (basically the Authorization header) as a basic encoded value.

-

Let’s ahead and call our service :

-
curl -X GET \
-  -H 'Otoroshi-Client-Id: my-first-api-key-id' \
-  -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \
-  'http://myservice.oto.tools:8080/api/test' --include
-
-

And with the second method :

-
curl -X GET \
-  -H 'Authorization: Basic bXktZmlyc3QtYXBpLWtleS1pZDpteS1maXJzdC1hcGkta2V5LXNlY3JldA==' \
-  'http://myservice.oto.tools:8080/api/test' --include
-
-
-

Tips : To easily fill your headers, you can jump to the Call examples section in each api key view. In this section the header names are the default values and the service url is not set. You have to adapt these lines to your case.

-
-

Override defaults headers names for a service

-

In some case, we want to change the defaults headers names (and it’s a quite good idea).

-

Let’s start by navigating to the Api keys Constraints section from the edit page of our sercice.

-

The first values to change are the headers names used to read the api key from client. Start by set :

-
    -
  • api-key-header-id as Custom client id header name
  • -
  • api-key-header-secret as Custom client secret header name
  • -
-

Save the service, and call the service again.

-
curl -X GET \
-  -H 'Otoroshi-Client-Id: my-first-api-key-id' \
-  -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \
-  'http://myservice.oto.tools:8080/api/test' --include
-
-

This should output an error because Otoroshi are expecting the api keys in other headers.

-
{
-  "Otoroshi-Error": "No ApiKey provided"
-}
-
-

Call one again the service but with the changed headers names.

-
curl -X GET \
-  -H 'api-key-header-id: my-first-api-key-id' \
-  -H 'api-key-header-secret: my-first-api-key-secret' \
-  'http://myservice.oto.tools:8080/api/test' --include
-
-

With this configuration, all others default services will accept the api keys with the Otoroshi-Client-Id and Otoroshi-Client-Secret headers, while our service, will accept the api-key-header-id and api-key-header-secret headers.

-

Accept only api keys with expected values

-

By default, a secure service only accepts requests with api key. But all generated api keys are eligible to call our service and in some case, we want authorize only a couple of api keys.

-

One feature of Otoroshi is to restrict the list of accepted api keys by giving a list of metadata or/and tags. Each api key has a list of tags and metadata, which can be used by Otoroshi to forward or not a call with an api key. All api key metadata/tags can be forward to your service (see Otoroshi exchange protocol section of a service to get more information about Send info. token).

-

Let’s starting by accept only the api keys which come with the tag of otoroshi as value.

-

Jump to the last part of the Api Keys Constraints section, call Routing constraints (these constraints are used to forward a call to a service, only if all constraints are validated).

-

In our first case, set otoroshi in One Tag in array and save the service. Then call our service with :

-
curl -X GET \
-  -H 'Otoroshi-Client-Id: my-first-api-key-id' \
-  -H 'Otoroshi-Client-Secret: my-first-api-key-secret' \
-  'http://myservice.oto.tools:8080/api/test' --include
-
-

This should output :

-
// Error reason : Our api key doesn't contains the expected tag.
-{
-  "Otoroshi-Error": "Bad API key"
-}
-
-

Navigate to the edit page of our api key, and jump to the Metadata and tags section. In this section, add otoroshi in Tags array, then save the api key. Call once again your call and you will normally get a successful response of our backend service.

-

In this example, we have restricted our service to be callable only with keys that have otoroshi as a tag.

-

But Otoroshi provides others behaviours. For each behaviour, Api key used should:

-
    -
  • All Tags in : have all of the following tags
  • -
  • No Tags in : not have one of the following tags
  • -
  • One Tag in : have at least one of the following tags
  • -
-
-
    -
  • All Meta. in : have all of the following metadata entries
  • -
  • No Meta. in : not have one of the following metadata entries
  • -
  • One Meta. in : have at least one of the following metadata entries
  • -
-
-
    -
  • One Meta key in : have at least one of the following key in metadata
  • -
  • All Meta key in : have all of the following keys in metadata
  • -
  • No Meta key in : not have one of the following keys in metadata
  • -
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-with-oauth1-client.html b/docs/manual/how-to-s/secure-with-oauth1-client.html deleted file mode 100644 index 5793691fef..0000000000 --- a/docs/manual/how-to-s/secure-with-oauth1-client.html +++ /dev/null @@ -1,508 +0,0 @@ - - - - -Secure an app with OAuth1 client flow · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an app with OAuth1 client flow

-

Before you start

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Running an simple OAuth 1 server

-

In this tutorial, we’ll instanciate a oauth 1 server with docker. If you alredy have the necessary, skip this section to.

-

Let’s start by running the server

-
docker run -d --name oauth1-server --rm \
-    -p 5000:5000 \
-    -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \
-    -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \
-    -e OAUTH1_REDIRECT_URI=http://otoroshi.oto.tools:8080/backoffice/auth0/callback \
-    ghcr.io/beryju/oauth1-test-server
-
-

We created a oauth 1 server which accepts http://otoroshi.oto.tools:8080/backoffice/auth0/callback as Redirect URI. This URL is used by Otoroshi to retrieve a token and a profile at the end of an authentication process.

-

After this command, the container logs should output :

-
127.0.0.1 - - [14/Oct/2021 12:10:49] "HEAD /api/health HTTP/1.1" 200 -
-
-

Create an OAuth 1 provider module

-
    -
  1. Go ahead, and navigate to http://otoroshi.oto.tools:8080
  2. -
  3. Click on the cog icon on the top right
  4. -
  5. Then Authentication configs button
  6. -
  7. And add a new configuration when clicking on the Add item button
  8. -
  9. Select the Oauth1 provider in the type selector field
  10. -
  11. Set a basic name and description like oauth1-provider
  12. -
  13. Set 2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET as Consumer key
  14. -
  15. Set wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp as Consumer secret
  16. -
  17. Set http://localhost:5000/oauth/request_token as Request Token URL
  18. -
  19. Set http://localhost:5000/oauth/authorize as Authorize URL
  20. -
  21. Set http://localhost:oauth/access_token as Access token URL
  22. -
  23. Set http://localhost:5000/api/me as Profile URL
  24. -
  25. Set http://otoroshi.oto.tools:8080/backoffice/auth0/callback as Callback URL
  26. -
  27. At the bottom of the page, disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)
  28. -
-

At this point, your configuration should be similar to :

- - -

With this configuration, the connected user will receive default access on teams and organizations. If you want to change the access rights for a specific user, you can achieve it with the Rights override field and a configuration like :

-
{
-  "foo@example.com": [
-    {
-      "tenant": "*:rw",
-      "teams": [
-        "*:rw"
-      ]
-    }
-  ]
-}
-
-

Save your configuration at the bottom of the page, then navigate to the danger zone to use your module as a third-party connection to the Otoroshi UI.

-

Connect to Otoroshi with OAuth1 authentication

-

To secure Otoroshi with your OAuth1 configuration, we have to register an Authentication configuration as a BackOffice Auth. configuration.

-
    -
  1. Navigate to the danger zone (when clicking on the cog on the top right and selecting Danger zone)
  2. -
  3. Scroll to the BackOffice auth. settings
  4. -
  5. Select your last Authentication configuration (created in the previous section)
  6. -
  7. Save the global configuration with the button on the top right
  8. -
-

Testing your configuration

-
    -
  1. Disconnect from your instance
  2. -
  3. Then click on the Login using third-party button (or navigate to http://otoroshi.oto.tools:8080)
  4. -
  5. Click on Login using Third-party button
  6. -
  7. If all is configured, Otoroshi will redirect you to the oauth 1 server login page
  8. -
  9. Set example-user as user and trust the user by clicking on yes button.
  10. -
  11. Good work! You’re connected to Otoroshi with an OAuth1 module.
  12. -
-
-

A fallback solution is always available in the event of a bad authentication configuration. By going to http://otoroshi.oto.tools:8080/bo/simple/login, the administrators will be able to redefine the configuration.

-
-

Secure an app with OAuth 1 authentication

-

With the previous configuration, you can secure any of Otoroshi services with it.

-

The first step is to apply a little change on the previous configuration.

-
    -
  1. Navigate to http://otoroshi.oto.tools:8080/bo/dashboard/auth-configs.
  2. -
  3. Create a new auth module configuration with the same values.
  4. -
  5. Replace the Callback URL field to http://privateapps.oto.tools:8080/privateapps/generic/callback (we changed this value because the redirection of a logged user by a third-party server is cover by an other route by Otoroshi).
  6. -
  7. Disable the secure button (because we’re using http and this configuration avoid to include cookie in an HTTP Request without secure channel, typically HTTPs)
  8. -
-
-

Note : an Otoroshi service is called a private app when it is protected by an authentication module.

-
-

Our example server supports only one redirect URI. We need to kill it, and to create a new container with http://otoroshi.oto.tools:8080/privateapps/generic/callback as OAUTH1_REDIRECT_URI

-
docker rm -f oauth1-server
-docker run -d --name oauth1-server --rm \
-    -p 5000:5000 \
-    -e OAUTH1_CLIENT_ID=2NVVBip7I5kfl0TwVmGzTphhC98kmXScpZaoz7ET \
-    -e OAUTH1_CLIENT_SECRET=wXzb8tGqXNbBQ5juA0ZKuFAmSW7RwOw8uSbdE3MvbrI8wjcbGp \
-    -e OAUTH1_REDIRECT_URI=http://privateapps.oto.tools:8080/privateapps/generic/callback \
-    ghcr.io/beryju/oauth1-test-server
-
-

Once the authentication module and the new container created, we can define the authentication module on the service.

-
    -
  1. Navigate to any created service
  2. -
  3. Scroll to Authentication section
  4. -
  5. Enable Enforce user authentication
  6. -
  7. Select your Authentication config inside the list
  8. -
  9. Enable Strict mode
  10. -
  11. Don’t forget to save your configuration.
  12. -
-

Now you can try to call your defined service and see the login module appears.

-
- -
-

The allow access to the user.

-
- -
-

If you had any errors, make sure of :

-
    -
  • check if you are on http or https, and if the secure cookie option is enabled or not on the authentication module
  • -
  • check if your OAuth1 server has the REDIRECT_URI set on privateapps/…
  • -
  • Make sure your server supports POST or GET OAuth1 flow set on authentication module
  • -
-

Once the configuration is working, you can check, when connecting with an Otoroshi admin user, the Private App session created (use the cog at the top right of the page, and select Priv. app sesssions, or navigate to http://otoroshi.oto.tools:8080/bo/dashboard/sessions/private).

-

One interesing feature is to check the profile of the connected user. In our case, when clicking on the Profile button of the right user, we should have :

-
{
-  "email": "foo@example.com",
-  "id": 1,
-  "name": "test name",
-  "screen_name": "example-user"
-}
-
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/secure-with-oauth2-client-credentials.html b/docs/manual/how-to-s/secure-with-oauth2-client-credentials.html deleted file mode 100644 index 3a222d0772..0000000000 --- a/docs/manual/how-to-s/secure-with-oauth2-client-credentials.html +++ /dev/null @@ -1,447 +0,0 @@ - - - - -Secure an app with OAuth2 client_credential flow · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Secure an app with OAuth2 client_credential flow

-

Otoroshi makes it easy for your app to implement the OAuth2 Client Credentials Flow. Following successful authentication, the calling application will have access to an Access Token, which can be used to call your protected APIs.

-

Deployed the Client Credential Service

-

The Client Credential Service must be enabled as a global plugin on your Otoroshi instance. To achieve that, navigate to your otoroshi instance (in our case http://otoroshi.oto.tools:8080) on the danger zone (top right cog icon / Danger zone or at /bo/dashboard/dangerzone).

-

To enable a plugin in global on Otoroshi, you must add it in the Global Plugins section.

-

Open the Global Plugin section, click on enabled (if not already done), and search the plugin named Client Credential Service of type Sink.

-

To show and add the default configuration on this plugin, click on the show config. panel an on the Inject default config. button. This button is available on each plugin and it’s useful when you want to inject the default configuration.

-

When you click on the show config. panel, you have the documentation of the plugin and its default configuration.

-

The client credential plugin has by default 4 parameters :

-
    -
  • domain: a regex used to exposed routes on each matching domain (default: *) -
  • -
  • expiration: duration until the token expire (in ms) (default: 3600000)
  • -
  • defaultKeyPair: a key pair used to sign the jwt token. By default, Otoroshi is deployed with an otoroshi-jwt-signing that you can visualize on the jwt verifiers certificates (default: “otoroshi-jwt-signing”)
  • -
  • secure: if enabled, Otoroshi will expose routes only in the https requests case (default: true)
  • -
-

In this tutorial, we will set the configuration as following :

-
    -
  • domain: *.oto.tools -
  • -
  • expiration: 3600000
  • -
  • defaultKeyPair: otoroshi-jwt-signing
  • -
  • secure: false
  • -
-

Now that the plugin is running, third routes are exposed on each matching domain of the regex.

-
    -
  • GET /.well-known/otoroshi/oauth/jwks.json : retrieve all public keys presents in Otoroshi
  • -
  • POST /.well-known/otoroshi/oauth/token/introspect : validate and decode the token
  • -
  • POST /.well-known/otoroshi/oauth/token : generate a token with the fields provided
  • -
-

Once the global configuration saved, we can deployed a simple service to test it.

-

Let’s navigate to the services page, and create a new service with :

-
    -
  1. http://foo.oto.tools:8080 as Exposed domain in Service exposition settings section
  2. -
  3. https://mirror.otoroshi.io as Target 1 in Service targets section
  4. -
  5. /.* as Private patterns in URL Patterns section (and remove all public patterns)
  6. -
-

In Api Keys Constraints, disabled From basic auth., Allow client id only usage and From custom headers button then saved the service.

-

Let’s make a first call, to check if the jwks are already exposed :

-
curl 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/jwks.json'
-
-

This should output a list of public keys :

-
{
-  "keys": [
-    {
-      "kty": "RSA",
-      "e": "AQAB",
-      "kid": "otoroshi-intermediate-ca",
-      ...
-    }
-    ...
-  ]
-}
-
-

Let’s make a call on a route of this service.

-
curl 'http://foo.oto.tools:8080/'
-
-

This should output the expected error:

-
{
-  "Otoroshi-Error": "No ApiKey provided"
-}
-
-

The first step is to generate an api key. Navigate to the api keys page, and create an item with the following values (it will be more easy to use them in the next step) :

-
    -
  • my-id as ApiKey Id
  • -
  • my-secret as ApiKey Secret
  • -
-

The next step is to ask a token by calling the exposed route /.well-known/otoroshi/oauth/jwks.json. The required fields are the grand type, the client and the client secret corresponding to our generated api key.

-
curl -X POST 'http://foo.oto.tools:8080/.well-known/otoroshi/oauth/token' \
-  -H "Content-Type: application/json" \
-  -d '{"grant_type":"client_credentials", "client_id":"my-id", "client_secret":"my-secret"}'
-
-

We have omit a parameter of the body which is named scope. This field can be used to set a bunch of scope on the generated access token.

-

The last command should output :

-
{
-  "access_token": "generated-token-xxxxx",
-  "token_type": "Bearer",
-  "expires_in": 3600
-}
-
-

Once generate, we can call our api again :

-
curl 'http://foo.oto.tools:8080/' \
-  -H "Authorization: Bearer generated-token-xxxxx"
-
-

This should output a list of headers with a field named Authorization containing the previous access token.

-

Other possible configuration

-

By default, Otoroshi generate the access token with the specified key pair in the configuration. But, in some case, you want a specific key pair by client_id/client_secret. You can achieve it when setting a jwt-sign-keypair metadata on your desired api key with the id of the key pair as value.

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/setup-otoroshi-cluster.html b/docs/manual/how-to-s/setup-otoroshi-cluster.html deleted file mode 100644 index 8ba1fdd9c3..0000000000 --- a/docs/manual/how-to-s/setup-otoroshi-cluster.html +++ /dev/null @@ -1,480 +0,0 @@ - - - - -Setup an Otoroshi cluster · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Setup an Otoroshi cluster

-

In this tutorial, we will deploy an Otoroshi cluster with one leader and 2 workers. We will add a load balancer in front of the workers and validate the installation by adding a header on the requests.

-

Let’s start by downloading the latest jar of Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

Then create an instance of Otoroshi and indicates with the otoroshi.cluster.mode environment variable that it will be the leader.

-
java -Dhttp.port=8091 -Dhttps.port=9091 -Dotoroshi.cluster.mode=leader -jar otoroshi.jar
-
-

Once created, we have to create the two workers. For both workers, we have to set the ip and the url of their leader in the otoroshi.cluster.leader.urls environment variable.

-

The first worker will listen on the :8082/:8092 ports

-
java \
-  -Dotoroshi.cluster.worker.name=worker-1 \
-  -Dhttp.port=8092 \
-  -Dhttps.port=9092 \
-  -Dotoroshi.cluster.mode=worker \
-  -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar
-
-

The second worker will listen on the :8083/:8093 ports

-
java \
-  -Dotoroshi.cluster.worker.name=worker-2 \
-  -Dhttp.port=8093 \
-  -Dhttps.port=9093 \
-  -Dotoroshi.cluster.mode=worker \
-  -Dotoroshi.cluster.leader.urls.0='http://127.0.0.1:8091' -jar otoroshi.jar
-
-

Once launched, you can navigate to the cluster view. If all is configured, you will see the leader, the 2 workers and a bunch of informations about each instance.

-

To complete our installation, we want to spread the incoming requests accross otoroshi worker instances.

-

In this tutorial, we will use haproxy has a TCP loadbalancer. If you don’t have haproxy installed, you can use docker to run an haproxy instance as explained below.

-

But first, we need an haproxy configuration file named haproxy.cfg with the following content :

-
frontend front_nodes_http
-    bind *:8080
-    mode tcp
-    default_backend back_http_nodes
-    timeout client          1m
-
-backend back_http_nodes
-    mode tcp
-    balance roundrobin
-    server node1 host.docker.internal:8092 # (1)
-    server node2 host.docker.internal:8093 # (1)
-    timeout connect        10s
-    timeout server          1m
-
-

and run haproxy with this config file

-
-
no docker
-
-
haproxy -c -f ./haproxy.cfg
-
docker (on linux) -
-
-
docker run -p 8080:8080 -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro --add-host=host.docker.internal:host-gateway haproxy
-
docker (on macos) -
-
-
docker run -p 8080:8080 -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy
-
docker (on windows) -
-
-
docker run -p 8080:8080 -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy
-
-

The last step is to create a service, add a rule to add, in the headers, a specific value to identify the worker used.

-

Create this service, exposed on http://myapi.oto.tools:xxxx, which will forward all requests to the mirror https://mirror.otoroshi.io.

-
curl -X POST http://otoroshi-api.oto.tools:8091/api/services \
--H "Content-type: application/json" \
--u admin-api-apikey-id:admin-api-apikey-secret \
--d @- <<'EOF'
-{
-    "enforceSecureCommunication": false,
-    "forceHttps": false,
-    "_loc": {
-        "tenant": "default",
-        "teams": [
-            "default"
-        ]
-    },
-    "groupId": "default",
-    "groups": [
-        "default"
-    ],
-    "id": "myapi",
-    "name": "myapi",
-    "description": "myapi",
-    "env": "prod",
-    "domain": "oto.tools",
-    "subdomain": "api",
-    "targetsLoadBalancing": {
-        "type": "RoundRobin"
-    },
-    "targets": [
-        {
-            "host": "mirror.otoroshi.io",
-            "scheme": "https",
-            "weight": 1,
-            "mtlsConfig": {
-                "certs": [],
-                "trustedCerts": [],
-                "mtls": false,
-                "loose": false,
-                "trustAll": false
-            },
-            "tags": [],
-            "metadata": {},
-            "protocol": "HTTP\/1.1",
-            "predicate": {
-                "type": "AlwaysMatch"
-            },
-            "ipAddress": null
-        }
-    ],
-    "root": "\/",
-    "matchingRoot": null,
-    "stripPath": true,
-    "enabled": true,
-    "publicPatterns": [
-        "/.*"
-    ],
-    "kind": "ServiceDescriptor",
-    "additionalHeaders": {
-        "worker-name": "${config.otoroshi.cluster.worker.name}"
-    }
-}
-EOF
-
-

Once created, call two times the service. If all is working, the header received by the backend service will have worker-1 and worker-2 as value.

-
curl 'http://api.oto.tools:8080'
-## Response headers
-{
-    ...
-    "worker-name": "worker-2"
-    ...
-}
-
-

This should output worker-1, then worker-2, etc. Well done, your loadbalancing is working and your cluster is set up correctly.

- -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/tls-termination-using-own-certificates.html b/docs/manual/how-to-s/tls-termination-using-own-certificates.html deleted file mode 100644 index 958a46ee7c..0000000000 --- a/docs/manual/how-to-s/tls-termination-using-own-certificates.html +++ /dev/null @@ -1,462 +0,0 @@ - - - - -TLS termination using your own certificates · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

TLS termination using your own certificates

-

The goal of this tutorial is to expose a service via https using a certificate generated by openssl.

If you already have an up and running otoroshi instance, you can skip the following instructions

-
-I want to follow the instructions to start an instance of Otorohi - -
-

Let’s start by downloading the latest Otoroshi.

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-
-

then you can run start Otoroshi :

-
java -Dotoroshi.adminPassword=password -jar otoroshi.jar 
-
-

Now you can log into Otoroshi at http://otoroshi.oto.tools:8080 with admin@otoroshi.io/password

-

Create a service, exposed on http://myservice.oto.tools:8080, which will forward all requests to the mirror https://mirror.otoroshi.io. Each call to this service will returned the body and the headers received by the mirror.

-
curl -X POST 'http://otoroshi-api.oto.tools:8080/api/services' \
-  -d '{"enforceSecureCommunication": false, "forceHttps": false, "_loc":{"tenant":"default","teams":["default"]},"groupId":"default","groups":["default"],"name":"my-service","description":"a service","env":"prod","domain":"oto.tools","subdomain":"myservice","targetsLoadBalancing":{"type":"RoundRobin"},"targets":[{"host":"mirror.otoroshi.io","scheme":"https","weight":1,"mtlsConfig":{"certs":[],"trustedCerts":[],"mtls":false,"loose":false,"trustAll":false},"tags":[],"metadata":{},"protocol":"HTTP\/1.1","predicate":{"type":"AlwaysMatch"},"ipAddress":null}],"root":"\/","matchingRoot":null,"stripPath":true,"enabled":true,"secComHeaders":{"claimRequestName":null,"stateRequestName":null,"stateResponseName":null},"publicPatterns":["\/.*"],"privatePatterns":[],"kind":"ServiceDescriptor"}' \
-  -H "Content-type: application/json" \
-  -u admin-api-apikey-id:admin-api-apikey-secret
-
-
-

Try to call the service.

-
curl 'http://myservice.oto.tools:8080'
-
-

This should output something like

-
{
-  "method": "GET",
-  "path": "/",
-  "headers": {
-    "host": "mirror.opunmaif.io",
-    "accept": "*/*",
-    "user-agent": "curl/7.64.1",
-    "x-forwarded-port": "443",
-    "opun-proxied-host": "mirror.otoroshi.io",
-    "otoroshi-request-id": "1463145856319359618",
-    "otoroshi-proxied-host": "myservice.oto.tools:8080",
-    "opun-gateway-request-id": "1463145856554240100",
-    "x-forwarded-proto": "https",
-  },
-  "body": ""
-}
-
-

Let’s try to call the service in https.

-
curl 'https://myservice.oto.tools:8443'
-
-

This should output

-
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myservice.oto.tools:8443
-
-

To fix it, we have to generate a certificate and import it in Otoroshi to match the domain myservice.oto.tools.

-
-

If you already had a certificate you can skip the next set of commands and directly import your certificate in Otoroshi

-
-

We will use openssl to generate a private key and a self-signed certificate.

-
openssl genrsa -out myservice.key 4096
-# remove pass phrase
-openssl rsa -in myservice.key -out myservice.key
-# generate the certificate authority cert
-openssl req -new -x509 -sha256 -days 730 -key myservice.key -out myservice.cer -subj "/CN=myservice.oto.tools"
-
-

Check the content of the certificate

-
openssl x509 -in myservice.cer -text
-
-

This should contains something like

-
Certificate:
-    Data:
-        Version: 1 (0x0)
-        Serial Number: 9572962808320067790 (0x84d9fef455f188ce)
-    Signature Algorithm: sha256WithRSAEncryption
-        Issuer: CN=myservice.oto.tools
-        Validity
-            Not Before: Nov 23 14:25:55 2021 GMT
-            Not After : Nov 23 14:25:55 2022 GMT
-        Subject: CN=myservice.oto.tools
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                Public-Key: (4096 bit)
-                Modulus:
-...
-
-

Once generated, go back to Otoroshi and navigate to the certificates management page (top right cog icon / SSL/TLS certificates or at /bo/dashboard/certificates) and click on Add item.

-

Set myservice-certificate as name and description.

-

Drop the myservice.cer file or copy the content to the Certificate full chain field.

-

Do the same action for the myservice.key file in the Certificate private key field.

-

Set your passphrase password in the private key password field if you added one.

-

Let’s try the same call to the service.

-
curl 'https://myservice.oto.tools:8443'
-
-

An error should occurs due to the untrsuted received certificate server

-
curl: (60) SSL certificate problem: self signed certificate
-More details here: https://curl.haxx.se/docs/sslcerts.html
-
-curl failed to verify the legitimacy of the server and therefore could not
-establish a secure connection to it. To learn more about this situation and
-how to fix it, please visit the web page mentioned above.
-
-

End this tutorial by trusting the certificate server

-
curl 'https://myservice.oto.tools:8443' --cacert myservice.cer
-
-

This should finally output

-
{
-  "method": "GET",
-  "path": "/",
-  "headers": {
-    "host": "mirror.opunmaif.io",
-    "accept": "*/*",
-    "user-agent": "curl/7.64.1",
-    "x-forwarded-port": "443",
-    "opun-proxied-host": "mirror.otoroshi.io",
-    "otoroshi-request-id": "1463158439730479893",
-    "otoroshi-proxied-host": "myservice.oto.tools:8443",
-    "opun-gateway-request-id": "1463158439558515871",
-    "x-forwarded-proto": "https",
-    "sozu-id": "01FN6MGKSYZNJYHEMP4R5PJ4Q5"
-  },
-  "body": ""
-}
-
- -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/how-to-s/tls-using-lets-encrypt.html b/docs/manual/how-to-s/tls-using-lets-encrypt.html deleted file mode 100644 index 9d94b5f20f..0000000000 --- a/docs/manual/how-to-s/tls-using-lets-encrypt.html +++ /dev/null @@ -1,371 +0,0 @@ - - - - -TLS termination using Lets Encrypt · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

TLS termination using Let’s Encrypt

-

As you know, Otoroshi is capable of doing TLS termination for your services. You can import your own certificates, generate certificates from scratch and you can also use the ACME protocol to generate certificates. One of the most popular service offering ACME certificates creation is Let’s Encrypt.

Warning
-

In order to make this tutorial work, your otoroshi instance MUST be accessible from the internet in order to be reachable by Let’s Encrypt ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.

Note
-

this tutorial can work with any ACME provider with the same rules. your otoroshi instance MUST be accessible by the ACME process. Also, the domain name used for the certificates MUST be configured to reach your otoroshi instance at your DNS provider level.

-

Setup let’s encrypt on otoroshi

-

Go on the danger zone page by clicking on the cog icon / Danger Zone. Scroll to the Let's Encrypt settings section. Enable it, and specify the address of the ACME server (for production Let’s Encrypt it’s acme://letsencrypt.org, for testing, it’s acme://letsencrypt.org/staging. Any ACME server address should work). You can also add one or more email addresses or contact urls that will be included in your Let’s Encrypt account. You don’t have to fill the public/private key inputs as they will be automatically generated on the first usage.

-

Creating let’s encrypt certificate from FQDNs

-

You can go to the certificates page by clicking on the cog icon / SSL/TLS Certificates. Here, click on the + Let's Encrypt certificate button. A popup will show up to ask you the FQDN that you want for you certificate. Once done, click on the Create button. A few moment later, you will be redirected on a brand new certificate generated by Let’s encrypt. You can now enjoy accessing your service behind the FQDN with TLS.

-

Creating let’s encrypt certificate from a service

-

You can go to any service page and enable the flag Issue Let's Encrypt cert.. Do not forget to save your service. A few moment later, the certificates will be available in the certificates page and you can will be able to enjoy accessing your service with TLS.

- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/imgs/amazon-ecs.png b/docs/manual/imgs/amazon-ecs.png deleted file mode 100644 index 3601458782..0000000000 Binary files a/docs/manual/imgs/amazon-ecs.png and /dev/null differ diff --git a/docs/manual/imgs/architecture-1-bis.png b/docs/manual/imgs/architecture-1-bis.png deleted file mode 100644 index 89aff27480..0000000000 Binary files a/docs/manual/imgs/architecture-1-bis.png and /dev/null differ diff --git a/docs/manual/imgs/architecture-1.png b/docs/manual/imgs/architecture-1.png deleted file mode 100644 index 7ab2243857..0000000000 Binary files a/docs/manual/imgs/architecture-1.png and /dev/null differ diff --git a/docs/manual/imgs/architecture-2-bis.png b/docs/manual/imgs/architecture-2-bis.png deleted file mode 100644 index b8359b490f..0000000000 Binary files a/docs/manual/imgs/architecture-2-bis.png and /dev/null differ diff --git a/docs/manual/imgs/architecture-2.png b/docs/manual/imgs/architecture-2.png deleted file mode 100644 index 649f47361a..0000000000 Binary files a/docs/manual/imgs/architecture-2.png and /dev/null differ diff --git a/docs/manual/imgs/azure-container-service.png b/docs/manual/imgs/azure-container-service.png deleted file mode 100644 index 0cf1efe70d..0000000000 Binary files a/docs/manual/imgs/azure-container-service.png and /dev/null differ diff --git a/docs/manual/imgs/cassandra.png b/docs/manual/imgs/cassandra.png deleted file mode 100644 index 177b66f667..0000000000 Binary files a/docs/manual/imgs/cassandra.png and /dev/null differ diff --git a/docs/manual/imgs/clever-cloud.png b/docs/manual/imgs/clever-cloud.png deleted file mode 100644 index 82492a0774..0000000000 Binary files a/docs/manual/imgs/clever-cloud.png and /dev/null differ diff --git a/docs/manual/imgs/cloudfoundry.png b/docs/manual/imgs/cloudfoundry.png deleted file mode 100644 index 00107a3ae9..0000000000 Binary files a/docs/manual/imgs/cloudfoundry.png and /dev/null differ diff --git a/docs/manual/imgs/cluster-3.png b/docs/manual/imgs/cluster-3.png deleted file mode 100644 index e7e35c744b..0000000000 Binary files a/docs/manual/imgs/cluster-3.png and /dev/null differ diff --git a/docs/manual/imgs/cluster-4.png b/docs/manual/imgs/cluster-4.png deleted file mode 100644 index 0f9dbfa027..0000000000 Binary files a/docs/manual/imgs/cluster-4.png and /dev/null differ diff --git a/docs/manual/imgs/cluster-5.jpg b/docs/manual/imgs/cluster-5.jpg deleted file mode 100644 index e301061e03..0000000000 Binary files a/docs/manual/imgs/cluster-5.jpg and /dev/null differ diff --git a/docs/manual/imgs/cluster-6.png b/docs/manual/imgs/cluster-6.png deleted file mode 100644 index 455da288c4..0000000000 Binary files a/docs/manual/imgs/cluster-6.png and /dev/null differ diff --git a/docs/manual/imgs/clustering.png b/docs/manual/imgs/clustering.png deleted file mode 100644 index 5e72821d87..0000000000 Binary files a/docs/manual/imgs/clustering.png and /dev/null differ diff --git a/docs/manual/imgs/daikoku-logo.png b/docs/manual/imgs/daikoku-logo.png deleted file mode 100644 index 8dd0b69e68..0000000000 Binary files a/docs/manual/imgs/daikoku-logo.png and /dev/null differ diff --git a/docs/manual/imgs/datastores.png b/docs/manual/imgs/datastores.png deleted file mode 100644 index 526ea7c809..0000000000 Binary files a/docs/manual/imgs/datastores.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-0.png b/docs/manual/imgs/deploy-cc-0.png deleted file mode 100644 index a965d50ea1..0000000000 Binary files a/docs/manual/imgs/deploy-cc-0.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-1.png b/docs/manual/imgs/deploy-cc-1.png deleted file mode 100644 index 2aa8bb705c..0000000000 Binary files a/docs/manual/imgs/deploy-cc-1.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-2.png b/docs/manual/imgs/deploy-cc-2.png deleted file mode 100644 index 0ae38a2cde..0000000000 Binary files a/docs/manual/imgs/deploy-cc-2.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-3.png b/docs/manual/imgs/deploy-cc-3.png deleted file mode 100644 index fefc22354c..0000000000 Binary files a/docs/manual/imgs/deploy-cc-3.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-4-bis.png b/docs/manual/imgs/deploy-cc-4-bis.png deleted file mode 100644 index a973c2f851..0000000000 Binary files a/docs/manual/imgs/deploy-cc-4-bis.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-4.png b/docs/manual/imgs/deploy-cc-4.png deleted file mode 100644 index a9035abf58..0000000000 Binary files a/docs/manual/imgs/deploy-cc-4.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-5.png b/docs/manual/imgs/deploy-cc-5.png deleted file mode 100644 index cc3b2a9b58..0000000000 Binary files a/docs/manual/imgs/deploy-cc-5.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-jar-0.png b/docs/manual/imgs/deploy-cc-jar-0.png deleted file mode 100644 index 3bb53e2a2c..0000000000 Binary files a/docs/manual/imgs/deploy-cc-jar-0.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-cc-jar-1.png b/docs/manual/imgs/deploy-cc-jar-1.png deleted file mode 100644 index e244081a8e..0000000000 Binary files a/docs/manual/imgs/deploy-cc-jar-1.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-0.png b/docs/manual/imgs/deploy-elb-0.png deleted file mode 100644 index 47f176a8a2..0000000000 Binary files a/docs/manual/imgs/deploy-elb-0.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-1.png b/docs/manual/imgs/deploy-elb-1.png deleted file mode 100644 index e52c64eb5f..0000000000 Binary files a/docs/manual/imgs/deploy-elb-1.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-10.png b/docs/manual/imgs/deploy-elb-10.png deleted file mode 100644 index 614dfa9d59..0000000000 Binary files a/docs/manual/imgs/deploy-elb-10.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-11.png b/docs/manual/imgs/deploy-elb-11.png deleted file mode 100644 index 9b3fc8f378..0000000000 Binary files a/docs/manual/imgs/deploy-elb-11.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-12.png b/docs/manual/imgs/deploy-elb-12.png deleted file mode 100644 index cef06c52f9..0000000000 Binary files a/docs/manual/imgs/deploy-elb-12.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-13.png b/docs/manual/imgs/deploy-elb-13.png deleted file mode 100644 index 78c531aee4..0000000000 Binary files a/docs/manual/imgs/deploy-elb-13.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-14.png b/docs/manual/imgs/deploy-elb-14.png deleted file mode 100644 index 69f4db325d..0000000000 Binary files a/docs/manual/imgs/deploy-elb-14.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-15.png b/docs/manual/imgs/deploy-elb-15.png deleted file mode 100644 index daca945f0d..0000000000 Binary files a/docs/manual/imgs/deploy-elb-15.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-16.png b/docs/manual/imgs/deploy-elb-16.png deleted file mode 100644 index 78846f84c3..0000000000 Binary files a/docs/manual/imgs/deploy-elb-16.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-17.png b/docs/manual/imgs/deploy-elb-17.png deleted file mode 100644 index a0c85b30cf..0000000000 Binary files a/docs/manual/imgs/deploy-elb-17.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-18.png b/docs/manual/imgs/deploy-elb-18.png deleted file mode 100644 index 2494ff350c..0000000000 Binary files a/docs/manual/imgs/deploy-elb-18.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-2.png b/docs/manual/imgs/deploy-elb-2.png deleted file mode 100644 index 157ac3849a..0000000000 Binary files a/docs/manual/imgs/deploy-elb-2.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-3.png b/docs/manual/imgs/deploy-elb-3.png deleted file mode 100644 index c1daab6c3b..0000000000 Binary files a/docs/manual/imgs/deploy-elb-3.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-4.png b/docs/manual/imgs/deploy-elb-4.png deleted file mode 100644 index 0af025fa7a..0000000000 Binary files a/docs/manual/imgs/deploy-elb-4.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-5.png b/docs/manual/imgs/deploy-elb-5.png deleted file mode 100644 index 96814636ec..0000000000 Binary files a/docs/manual/imgs/deploy-elb-5.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-6.png b/docs/manual/imgs/deploy-elb-6.png deleted file mode 100644 index 2d27be8127..0000000000 Binary files a/docs/manual/imgs/deploy-elb-6.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-7.png b/docs/manual/imgs/deploy-elb-7.png deleted file mode 100644 index 60c3e63eb4..0000000000 Binary files a/docs/manual/imgs/deploy-elb-7.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-8.png b/docs/manual/imgs/deploy-elb-8.png deleted file mode 100644 index a59130cd7a..0000000000 Binary files a/docs/manual/imgs/deploy-elb-8.png and /dev/null differ diff --git a/docs/manual/imgs/deploy-elb-9.png b/docs/manual/imgs/deploy-elb-9.png deleted file mode 100644 index 9ff31e9409..0000000000 Binary files a/docs/manual/imgs/deploy-elb-9.png and /dev/null differ diff --git a/docs/manual/imgs/documentation.png b/docs/manual/imgs/documentation.png deleted file mode 100644 index a0bc2b58fc..0000000000 Binary files a/docs/manual/imgs/documentation.png and /dev/null differ diff --git a/docs/manual/imgs/elastic-beanstalk.png b/docs/manual/imgs/elastic-beanstalk.png deleted file mode 100644 index 128af796d5..0000000000 Binary files a/docs/manual/imgs/elastic-beanstalk.png and /dev/null differ diff --git a/docs/manual/imgs/entities-certificates.png b/docs/manual/imgs/entities-certificates.png deleted file mode 100644 index 3fa31e9e3e..0000000000 Binary files a/docs/manual/imgs/entities-certificates.png and /dev/null differ diff --git a/docs/manual/imgs/entities-danger-zone.png b/docs/manual/imgs/entities-danger-zone.png deleted file mode 100644 index daa7697fd4..0000000000 Binary files a/docs/manual/imgs/entities-danger-zone.png and /dev/null differ diff --git a/docs/manual/imgs/entities-exporters.png b/docs/manual/imgs/entities-exporters.png deleted file mode 100644 index 7107484690..0000000000 Binary files a/docs/manual/imgs/entities-exporters.png and /dev/null differ diff --git a/docs/manual/imgs/entities-groups.png b/docs/manual/imgs/entities-groups.png deleted file mode 100644 index 5045ea1185..0000000000 Binary files a/docs/manual/imgs/entities-groups.png and /dev/null differ diff --git a/docs/manual/imgs/entities-keys.png b/docs/manual/imgs/entities-keys.png deleted file mode 100644 index b75cd3e47b..0000000000 Binary files a/docs/manual/imgs/entities-keys.png and /dev/null differ diff --git a/docs/manual/imgs/entities-plugins.png b/docs/manual/imgs/entities-plugins.png deleted file mode 100644 index d893199887..0000000000 Binary files a/docs/manual/imgs/entities-plugins.png and /dev/null differ diff --git a/docs/manual/imgs/entities-security.png b/docs/manual/imgs/entities-security.png deleted file mode 100644 index 5462ff06cf..0000000000 Binary files a/docs/manual/imgs/entities-security.png and /dev/null differ diff --git a/docs/manual/imgs/entities-services.png b/docs/manual/imgs/entities-services.png deleted file mode 100644 index 059ed5f23b..0000000000 Binary files a/docs/manual/imgs/entities-services.png and /dev/null differ diff --git a/docs/manual/imgs/exchange-2.png b/docs/manual/imgs/exchange-2.png deleted file mode 100644 index 2997395599..0000000000 Binary files a/docs/manual/imgs/exchange-2.png and /dev/null differ diff --git a/docs/manual/imgs/exchange.png b/docs/manual/imgs/exchange.png deleted file mode 100644 index ba6d573f14..0000000000 Binary files a/docs/manual/imgs/exchange.png and /dev/null differ diff --git a/docs/manual/imgs/filedb.png b/docs/manual/imgs/filedb.png deleted file mode 100644 index 392f6d391f..0000000000 Binary files a/docs/manual/imgs/filedb.png and /dev/null differ diff --git a/docs/manual/imgs/generated-hows-to-ldap-auth-configs.png b/docs/manual/imgs/generated-hows-to-ldap-auth-configs.png deleted file mode 100644 index ef30cedd13..0000000000 Binary files a/docs/manual/imgs/generated-hows-to-ldap-auth-configs.png and /dev/null differ diff --git a/docs/manual/imgs/generated-hows-to-ldap-manage-users.png b/docs/manual/imgs/generated-hows-to-ldap-manage-users.png deleted file mode 100644 index e9a8036c1c..0000000000 Binary files a/docs/manual/imgs/generated-hows-to-ldap-manage-users.png and /dev/null differ diff --git a/docs/manual/imgs/generated-hows-to-secure-an-app-with-ldap.png b/docs/manual/imgs/generated-hows-to-secure-an-app-with-ldap.png deleted file mode 100644 index 15e33323d3..0000000000 Binary files a/docs/manual/imgs/generated-hows-to-secure-an-app-with-ldap.png and /dev/null differ diff --git a/docs/manual/imgs/generated-index-md-home.png b/docs/manual/imgs/generated-index-md-home.png deleted file mode 100644 index dcde5638d8..0000000000 Binary files a/docs/manual/imgs/generated-index-md-home.png and /dev/null differ diff --git a/docs/manual/imgs/google.jpeg b/docs/manual/imgs/google.jpeg deleted file mode 100644 index f353cf3ad2..0000000000 Binary files a/docs/manual/imgs/google.jpeg and /dev/null differ diff --git a/docs/manual/imgs/heroku.png b/docs/manual/imgs/heroku.png deleted file mode 100644 index 78953df30c..0000000000 Binary files a/docs/manual/imgs/heroku.png and /dev/null differ diff --git a/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-input.png b/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-input.png deleted file mode 100644 index b1105e0c0b..0000000000 Binary files a/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-input.png and /dev/null differ diff --git a/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-trust.png b/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-trust.png deleted file mode 100644 index 2dd93f7c6e..0000000000 Binary files a/docs/manual/imgs/hows-to-secure-app-with-oauth1-provider-trust.png and /dev/null differ diff --git a/docs/manual/imgs/inmemory.png b/docs/manual/imgs/inmemory.png deleted file mode 100644 index edb29779cb..0000000000 Binary files a/docs/manual/imgs/inmemory.png and /dev/null differ diff --git a/docs/manual/imgs/jwt-token-keypair-validation.png b/docs/manual/imgs/jwt-token-keypair-validation.png deleted file mode 100644 index 3de31c45e7..0000000000 Binary files a/docs/manual/imgs/jwt-token-keypair-validation.png and /dev/null differ diff --git a/docs/manual/imgs/kubernetes-daikoku-integration-enabled.png b/docs/manual/imgs/kubernetes-daikoku-integration-enabled.png deleted file mode 100644 index b8a0b803bb..0000000000 Binary files a/docs/manual/imgs/kubernetes-daikoku-integration-enabled.png and /dev/null differ diff --git a/docs/manual/imgs/kubernetes-daikoku-integration-token.png b/docs/manual/imgs/kubernetes-daikoku-integration-token.png deleted file mode 100644 index 661a86daf9..0000000000 Binary files a/docs/manual/imgs/kubernetes-daikoku-integration-token.png and /dev/null differ diff --git a/docs/manual/imgs/kubernetes.png b/docs/manual/imgs/kubernetes.png deleted file mode 100644 index 13cb03cbb6..0000000000 Binary files a/docs/manual/imgs/kubernetes.png and /dev/null differ diff --git a/docs/manual/imgs/models-apikey.png b/docs/manual/imgs/models-apikey.png deleted file mode 100644 index da3dff280d..0000000000 Binary files a/docs/manual/imgs/models-apikey.png and /dev/null differ diff --git a/docs/manual/imgs/models-group.png b/docs/manual/imgs/models-group.png deleted file mode 100644 index f40b69ff2a..0000000000 Binary files a/docs/manual/imgs/models-group.png and /dev/null differ diff --git a/docs/manual/imgs/models-service.png b/docs/manual/imgs/models-service.png deleted file mode 100644 index 5017a00ae6..0000000000 Binary files a/docs/manual/imgs/models-service.png and /dev/null differ diff --git a/docs/manual/imgs/mtls-arch-1.jpg b/docs/manual/imgs/mtls-arch-1.jpg deleted file mode 100644 index 0e9adc85d6..0000000000 Binary files a/docs/manual/imgs/mtls-arch-1.jpg and /dev/null differ diff --git a/docs/manual/imgs/mtls-arch-2.jpg b/docs/manual/imgs/mtls-arch-2.jpg deleted file mode 100644 index 54c780f827..0000000000 Binary files a/docs/manual/imgs/mtls-arch-2.jpg and /dev/null differ diff --git a/docs/manual/imgs/opensource.png b/docs/manual/imgs/opensource.png deleted file mode 100644 index c486ce9d07..0000000000 Binary files a/docs/manual/imgs/opensource.png and /dev/null differ diff --git a/docs/manual/imgs/organizations-and-teams.png b/docs/manual/imgs/organizations-and-teams.png deleted file mode 100644 index 3b52bf9c98..0000000000 Binary files a/docs/manual/imgs/organizations-and-teams.png and /dev/null differ diff --git a/docs/manual/imgs/paste.png b/docs/manual/imgs/paste.png deleted file mode 100644 index 10742359eb..0000000000 Binary files a/docs/manual/imgs/paste.png and /dev/null differ diff --git a/docs/manual/imgs/postgres.png b/docs/manual/imgs/postgres.png deleted file mode 100644 index f450650f7e..0000000000 Binary files a/docs/manual/imgs/postgres.png and /dev/null differ diff --git a/docs/manual/imgs/push-to-elastic.png b/docs/manual/imgs/push-to-elastic.png deleted file mode 100644 index 300e3d03e8..0000000000 Binary files a/docs/manual/imgs/push-to-elastic.png and /dev/null differ diff --git a/docs/manual/imgs/redis.png b/docs/manual/imgs/redis.png deleted file mode 100644 index 2e6d62868b..0000000000 Binary files a/docs/manual/imgs/redis.png and /dev/null differ diff --git a/docs/manual/imgs/route_comp_openapi_import.png b/docs/manual/imgs/route_comp_openapi_import.png deleted file mode 100644 index f23d26b344..0000000000 Binary files a/docs/manual/imgs/route_comp_openapi_import.png and /dev/null differ diff --git a/docs/manual/imgs/scaling.png b/docs/manual/imgs/scaling.png deleted file mode 100644 index 67755fecf8..0000000000 Binary files a/docs/manual/imgs/scaling.png and /dev/null differ diff --git a/docs/manual/imgs/scripts-1.png b/docs/manual/imgs/scripts-1.png deleted file mode 100644 index 85069f288e..0000000000 Binary files a/docs/manual/imgs/scripts-1.png and /dev/null differ diff --git a/docs/manual/imgs/scripts-2.png b/docs/manual/imgs/scripts-2.png deleted file mode 100644 index 772d45b901..0000000000 Binary files a/docs/manual/imgs/scripts-2.png and /dev/null differ diff --git a/docs/manual/imgs/sec-com-signing-2-bis.png b/docs/manual/imgs/sec-com-signing-2-bis.png deleted file mode 100644 index 223fef6749..0000000000 Binary files a/docs/manual/imgs/sec-com-signing-2-bis.png and /dev/null differ diff --git a/docs/manual/imgs/sec-com-signing-2.png b/docs/manual/imgs/sec-com-signing-2.png deleted file mode 100644 index 6d88f6cbac..0000000000 Binary files a/docs/manual/imgs/sec-com-signing-2.png and /dev/null differ diff --git a/docs/manual/imgs/sec-com-signing-bis.png b/docs/manual/imgs/sec-com-signing-bis.png deleted file mode 100644 index 8ebcd37c6f..0000000000 Binary files a/docs/manual/imgs/sec-com-signing-bis.png and /dev/null differ diff --git a/docs/manual/imgs/sec-com-signing.png b/docs/manual/imgs/sec-com-signing.png deleted file mode 100644 index b724a9237f..0000000000 Binary files a/docs/manual/imgs/sec-com-signing.png and /dev/null differ diff --git a/docs/manual/imgs/secure-an-app-with-jwt-verifiers-jwtio.png b/docs/manual/imgs/secure-an-app-with-jwt-verifiers-jwtio.png deleted file mode 100644 index fe9379373c..0000000000 Binary files a/docs/manual/imgs/secure-an-app-with-jwt-verifiers-jwtio.png and /dev/null differ diff --git a/docs/manual/imgs/secure-an-app-with-jwt-verifiers-transform-jwtio.png b/docs/manual/imgs/secure-an-app-with-jwt-verifiers-transform-jwtio.png deleted file mode 100644 index 5840d30661..0000000000 Binary files a/docs/manual/imgs/secure-an-app-with-jwt-verifiers-transform-jwtio.png and /dev/null differ diff --git a/docs/manual/imgs/service-analytics.png b/docs/manual/imgs/service-analytics.png deleted file mode 100644 index 9fa513b6c2..0000000000 Binary files a/docs/manual/imgs/service-analytics.png and /dev/null differ diff --git a/docs/manual/imgs/service-healthcheck.png b/docs/manual/imgs/service-healthcheck.png deleted file mode 100644 index 6de923fcaf..0000000000 Binary files a/docs/manual/imgs/service-healthcheck.png and /dev/null differ diff --git a/docs/manual/imgs/service-live-stats.png b/docs/manual/imgs/service-live-stats.png deleted file mode 100644 index e4277aa41a..0000000000 Binary files a/docs/manual/imgs/service-live-stats.png and /dev/null differ diff --git a/docs/manual/imgs/small-otoroshi-logo-xmas.png b/docs/manual/imgs/small-otoroshi-logo-xmas.png deleted file mode 100644 index 44812ccc85..0000000000 Binary files a/docs/manual/imgs/small-otoroshi-logo-xmas.png and /dev/null differ diff --git a/docs/manual/imgs/small-otoroshi-logo.png b/docs/manual/imgs/small-otoroshi-logo.png deleted file mode 100644 index fc393e3edc..0000000000 Binary files a/docs/manual/imgs/small-otoroshi-logo.png and /dev/null differ diff --git a/docs/manual/imgs/snow-monkey-faults.png b/docs/manual/imgs/snow-monkey-faults.png deleted file mode 100644 index ff53cac7cb..0000000000 Binary files a/docs/manual/imgs/snow-monkey-faults.png and /dev/null differ diff --git a/docs/manual/imgs/snow-monkey-outages.png b/docs/manual/imgs/snow-monkey-outages.png deleted file mode 100644 index 4381ff45fb..0000000000 Binary files a/docs/manual/imgs/snow-monkey-outages.png and /dev/null differ diff --git a/docs/manual/imgs/snow-monkey-settings.png b/docs/manual/imgs/snow-monkey-settings.png deleted file mode 100644 index 7dcde5873c..0000000000 Binary files a/docs/manual/imgs/snow-monkey-settings.png and /dev/null differ diff --git a/docs/manual/imgs/snow-monkey-start.png b/docs/manual/imgs/snow-monkey-start.png deleted file mode 100644 index 5e0be102fd..0000000000 Binary files a/docs/manual/imgs/snow-monkey-start.png and /dev/null differ diff --git a/docs/manual/imgs/snow-monkey.png b/docs/manual/imgs/snow-monkey.png deleted file mode 100644 index 06742241fb..0000000000 Binary files a/docs/manual/imgs/snow-monkey.png and /dev/null differ diff --git a/docs/manual/imgs/tls-call-settings.png b/docs/manual/imgs/tls-call-settings.png deleted file mode 100644 index 5bacef6f10..0000000000 Binary files a/docs/manual/imgs/tls-call-settings.png and /dev/null differ diff --git a/docs/manual/index.html b/docs/manual/index.html deleted file mode 100644 index 8be6d0a638..0000000000 --- a/docs/manual/index.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - -Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Otoroshi

-

Otoroshi is a layer of lightweight api management on top of a modern http reverse proxy written in Scala and developped by the MAIF OSS team that can handle all the calls to and between your microservices without service locator and let you change configuration dynamicaly at runtime.

-
-

The Otoroshi is a large hairy monster that tends to lurk on the top of the torii gate in front of Shinto shrines. It’s a hostile creature, but also said to be the guardian of the shrine and is said to leap down from the top of the gate to devour those who approach the shrine for only self-serving purposes.

-
-

build Join the chat at https://gitter.im/MAIF/otoroshi Download

-
-

Installation

-

You can download the latest build of Otoroshi as a fat jar, as a zip package or as a docker image.

-

You can install and run Otoroshi with this little bash snippet

-
curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar'
-java -jar otoroshi.jar
-
-

or using docker

-
docker run -p "8080:8080" maif/otoroshi:1.5.11
-
-

now open your browser to http://otoroshi.oto.tools:8080/, log in with the credential generated in the logs and explore by yourself, if you want better instructions, just go to the Quick Start or directly to the installation instructions

-

Documentation

- -

Discussion

-

Join the Otoroshi channel on the MAIF Gitter { open=new }

-

Sources

-

The sources of Otoroshi are available on Github.

-

Logo

-

You can find the official Otoroshi logo on GitHub. The Otoroshi logo has been created by François Galioto (@fgalioto)

-

Changelog

-

Every release, along with the migration instructions, is documented on the Github Releases page. A condensed version of the changelog is available on github

-

Patrons

-

The work on Otoroshi was funded by MAIF with the help of the community.

-

Licence

-

Otoroshi is Open Source and available under the Apache 2 License

- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/install/get-otoroshi.html b/docs/manual/install/get-otoroshi.html deleted file mode 100644 index 903f5f3122..0000000000 --- a/docs/manual/install/get-otoroshi.html +++ /dev/null @@ -1,380 +0,0 @@ - - - - -Get Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Get Otoroshi

-

All release can be bound on the releases page of the repository.

-

From zip

-
# Download the latest version
-wget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi-1.5.11.zip
-unzip ./otoroshi-1.5.11.zip
-cd otoroshi-1.5.11
-
-

From jar file

-
# Download the latest version
-wget https://github.com/MAIF/otoroshi/releases/download/v1.5.11/otoroshi.jar
-
-

From Docker

-
# Download the latest version
-docker pull maif/otoroshi:1.5.11-jdk11
-
-

From Sources

-

To build Otoroshi from sources, just go to the dev documentation

- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/install/index.html b/docs/manual/install/index.html deleted file mode 100644 index 8212ed72f8..0000000000 --- a/docs/manual/install/index.html +++ /dev/null @@ -1,352 +0,0 @@ - - - - -Install · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Install

-

In this sections, you will find informations about how to install and run Otoroshi

- - -
-
-
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/install/run-otoroshi.html b/docs/manual/install/run-otoroshi.html deleted file mode 100644 index 9fe396498e..0000000000 --- a/docs/manual/install/run-otoroshi.html +++ /dev/null @@ -1,427 +0,0 @@ - - - - -Run Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Run Otoroshi

-

Now you are ready to run Otoroshi. You can run the following command with some tweaks depending on the way you want to configure Otoroshi. If you want to pass a custom configuration file, use the -Dconfig.file=/path/to/file.conf flag in the following commands.

-

From .zip file

-
cd otoroshi-vx.x.x
-./bin/otoroshi
-
-

From .jar file

-

For Java 11

-
java -jar otoroshi.jar
-
-

if you want to run the jar file for on a JDK above JDK11, you’ll have to add the following flags

-
java \
-  --add-opens=java.base/javax.net.ssl=ALL-UNNAMED \
-  --add-opens=java.base/sun.net.www.protocol.file=ALL-UNNAMED \
-  --add-exports=java.base/sun.security.x509=ALL-UNNAMED \
-  --add-opens=java.base/sun.security.ssl=ALL-UNNAMED \
-  -Dlog4j2.formatMsgNoLookups=true \
-  -jar otoroshi.jar
-
-

From docker

-
docker run -p "8080:8080" maif/otoroshi
-
-

You can also pass useful args like :

-
docker run -p "8080:8080" maif/otoroshi -Dconfig.file=/usr/app/otoroshi/conf/otoroshi.conf -Dlogger.file=/usr/app/otoroshi/conf/otoroshi.xml
-
-

If you want to provide your own config file, you can read the documentation about config files.

-

You can also provide some ENV variable using the --env flag to customize your Otoroshi instance.

-

The list of possible env variables is available here.

-

You can use a volume to provide configuration like :

-
docker run -p "8080:8080" -v "$(pwd):/usr/app/otoroshi/conf" maif/otoroshi
-
-

You can also use a volume if you choose to use filedb datastore like :

-
docker run -p "8080:8080" -v "$(pwd)/filedb:/usr/app/otoroshi/filedb" maif/otoroshi -Dotoroshi.storage=file
-
-

You can also use a volume if you choose to use exports files :

-
docker run -p "8080:8080" -v "$(pwd):/usr/app/otoroshi/imports" maif/otoroshi -Dotoroshi.importFrom=/usr/app/otoroshi/imports/export.json
-
-

Run examples

-
$ java \
-  -Xms2G \
-  -Xmx8G \
-  -Dhttp.port=8080 \
-  -Dotoroshi.importFrom=/home/user/otoroshi.json \
-  -Dconfig.file=/home/user/otoroshi.conf \
-  -jar ./otoroshi.jar
-
-[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores
-[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services
-[warn] otoroshi-env - Importing from: /home/user/otoroshi.json
-[info] play.api.Play - Application started (Prod)
-[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080
-
-

If you choose to start Otoroshi without importing existing data, Otoroshi will create a new admin user and print the login details in the log. When you will log into the admin dashboard, Otoroshi will ask you to create another account to avoid security issues.

-
$ java \
-  -Xms2G \
-  -Xmx8G \
-  -Dhttp.port=8080 \
-  -jar otoroshi.jar
-
-[warn] otoroshi-in-memory-datastores - Now using InMemory DataStores
-[warn] otoroshi-env - The main datastore seems to be empty, registering some basic services
-[warn] otoroshi-env - You can log into the Otoroshi admin console with the following credentials: admin@otoroshi.io / HHUsiF2UC3OPdmg0lGngEv3RrbIwWV5W
-[info] play.api.Play - Application started (Prod)
-[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080
-
- -
-
- -
-
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/install/setup-otoroshi.html b/docs/manual/install/setup-otoroshi.html deleted file mode 100644 index 63730731c7..0000000000 --- a/docs/manual/install/setup-otoroshi.html +++ /dev/null @@ -1,3249 +0,0 @@ - - - - -Setup Otoroshi · Otoroshi - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- -
- - - -
- -
- -
- -
-
- - - -
-
-

Setup Otoroshi

-

in this section we are going to configure otoroshi before running it for the first time

-

Setup the database

-

Right now, Otoroshi supports multiple datastore. You can choose one datastore over another depending on your use case.

-
Redis
- -

The redis datastore is quite nice when you want to easily deploy several Otoroshi instances.

- -

Documentation

-
In memory
-

The in-memory datastore is kind of interesting. It can be used for testing purposes, but it is also a good candidate for production because of its fastness.

- -

Start with

-
Cassandra
-
Clustering
-

Experimental support, should be used in cluster mode for leaders

- -

Documentation

-
Postgresql
-
Clustering
-

Or any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)

- -

Documentation

-
FileDB
-

The filedb datastore is pretty handy for testing purposes, but is not supposed to be used in production mode. Not suitable for production usage.

-
-
-

the first thing to setup is what kind of datastore you want to use with the otoroshi.storage setting

-
otoroshi {
-  storage = "inmemory" # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg             
-  storage = ${?APP_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg  
-  storage = ${?OTOROSHI_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg  
-}
-
-

depending on the value you chose, you will be able to configure your datastore with the following configuration

-
-
inmemory
-
-
otoroshi {
-  inmemory { # configuration to fetch/store otoroshi state in memory
-    windowSize = 99
-    windowSize = ${?INMEMORY_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_INMEMORY_WINDOW_SIZE}
-    experimental = false
-    experimental = ${?INMEMORY_EXPERIMENTAL_STORE}
-    experimental = ${?OTOROSHI_INMEMORY_EXPERIMENTAL_STORE}
-    optimized = false
-    optimized = ${?INMEMORY_OPTIMIZED}
-    optimized = ${?OTOROSHI_INMEMORY_OPTIMIZED}
-    modern = false
-    modern =  ${?INMEMORY_MODERN}
-    modern =  ${?OTOROSHI_INMEMORY_MODERN}
-  }
-}
-
file
-
-
otoroshi {
-  filedb { # configuration to fetch/store otoroshi state from a file
-    windowSize = 99
-    windowSize = ${?FILEDB_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_FILEDB_WINDOW_SIZE}
-    path = "./filedb/state.ndjson"
-    path = ${?FILEDB_PATH}
-    path = ${?OTOROSHI_FILEDB_PATH}
-  }
-}
-
http
-
-
otoroshi {
-  httpdb { # configuration to fetch/store otoroshi state from an http endpoint
-    url = "http://127.0.0.1:8888/worker-0/state.json"
-    headers = {}
-    timeout = 10000
-    pollEvery = 10000
-  }
-}
-
s3
-
-
otoroshi {
-  s3db { # configuration to fetch/store otoroshi state from a S3 bucket
-    bucket = "otoroshi-states"
-    bucket = ${?OTOROSHI_DB_S3_BUCKET}
-    endpoint = "https://otoroshi-states.foo.bar"
-    endpoint = ${?OTOROSHI_DB_S3_ENDPOINT}
-    region = "eu-west-1"
-    region = ${?OTOROSHI_DB_S3_REGION}
-    access = "secret"
-    access = ${?OTOROSHI_DB_S3_ACCESS}
-    secret = "secret"
-    secret = ${?OTOROSHI_DB_S3_SECRET}
-    key = "/otoroshi/states/state"
-    key = ${?OTOROSHI_DB_S3_KEY}
-    chunkSize = 8388608
-    chunkSize = ${?OTOROSHI_DB_S3_CHUNK_SIZE}
-    v4auth = true
-    v4auth = ${?OTOROSHI_DB_S3_V4_AUTH}
-    writeEvery = 60000 # write interval
-    writeEvery = ${?OTOROSHI_DB_S3_WRITE_EVERY} # write interval
-    acl = "Private"
-    acl = ${?OTOROSHI_DB_S3_ACL}
-  }
-}
-
redis
-
-
otoroshi {
-  redis { # configuration to fetch/store otoroshi state from a redis datastore using rediscala
-    host = "localhost"
-    host = ${?REDIS_HOST}
-    host = ${?OTOROSHI_REDIS_HOST}
-    port = 6379
-    port = ${?REDIS_PORT}
-    port = ${?OTOROSHI_REDIS_PORT}
-    password = ${?REDIS_PASSWORD}
-    password = ${?OTOROSHI_REDIS_PASSWORD}
-    windowSize = 99
-    windowSize = ${?REDIS_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_REDIS_WINDOW_SIZE}
-    slaves = []
-    slavesStr = ${?REDIS_SLAVES}
-    slavesStr = ${?OTOROSHI_REDIS_SLAVES}
-    slavesStr = ${?REDIS_MEMBERS}
-    slavesStr = ${?OTOROSHI_REDIS_MEMBERS}
-    useScan = false
-    useScan =  ${?REDIS_USE_SCAN}
-    useScan =  ${?OTOROSHI_REDIS_USE_SCAN}
-
-    pool {
-      members = []
-      members = ${?REDIS_POOL_MEMBERS}
-      members = ${?OTOROSHI_REDIS_POOL_MEMBERS}
-    }
-
-    mpool {
-      members = []
-      membersStr = ${?REDIS_MPOOL_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_MPOOL_MEMBERS}
-    }
-
-    lf {
-      master {
-        host = ${?REDIS_LF_HOST}
-        host = ${?OTOROSHI_REDIS_LF_HOST}
-        port = ${?REDIS_LF_PORT}
-        port = ${?OTOROSHI_REDIS_LF_PORT}
-        password = ${?REDIS_LF_PASSWORD}
-        password = ${?OTOROSHI_REDIS_LF_PASSWORD}
-      }
-      slaves = []
-      slavesStr = ${?REDIS_LF_SLAVES}
-      slavesStr = ${?OTOROSHI_REDIS_LF_SLAVES}
-      slavesStr = ${?REDIS_LF_MEMBERS}
-      slavesStr = ${?OTOROSHI_REDIS_LF_MEMBERS}
-    }
-
-    sentinels {
-      master = ${?REDIS_SENTINELS_MASTER}
-      master = ${?OTOROSHI_REDIS_SENTINELS_MASTER}
-      password = ${?REDIS_SENTINELS_PASSWORD}
-      password = ${?OTOROSHI_REDIS_SENTINELS_PASSWORD}
-      db = ${?REDIS_SENTINELS_DB}
-      db = ${?OTOROSHI_REDIS_SENTINELS_DB}
-      name = ${?REDIS_SENTINELS_NAME}
-      name = ${?OTOROSHI_REDIS_SENTINELS_NAME}
-      members = []
-      membersStr = ${?REDIS_SENTINELS_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_SENTINELS_MEMBERS}
-
-      lf {
-        master = ${?REDIS_SENTINELS_LF_MASTER}
-        master = ${?OTOROSHI_REDIS_SENTINELS_LF_MASTER}
-        members = []
-        membersStr = ${?REDIS_SENTINELS_LF_MEMBERS}
-        membersStr = ${?OTOROSHI_REDIS_SENTINELS_LF_MEMBERS}
-      }
-    }
-
-    cluster {
-      members = []
-      membersStr = ${?REDIS_CLUSTER_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_CLUSTER_MEMBERS}
-    }
-  }
-}
-
redis with lettuce
-
-
otoroshi {
-  redis { 
-    lettuce { # configuration to fetch/store otoroshi state from a redis datastore using the lettuce driver (the next default one)
-      connection = "default"
-      connection = ${?REDIS_LETTUCE_CONNECTION}
-      connection = ${?OTOROSHI_REDIS_LETTUCE_CONNECTION}
-      uri =  ${?REDIS_LETTUCE_URI}
-      uri =  ${?OTOROSHI_REDIS_LETTUCE_URI}
-      uri =  ${?REDIS_URL}
-      uri =  ${?OTOROSHI_REDIS_URL}
-      uris = []
-      urisStr = ${?REDIS_LETTUCE_URIS}
-      urisStr = ${?OTOROSHI_REDIS_LETTUCE_URIS}
-      readFrom = "MASTER_PREFERRED"
-      readFrom = ${?REDIS_LETTUCE_READ_FROM}
-      readFrom = ${?OTOROSHI_REDIS_LETTUCE_READ_FROM}
-      startTLS = false
-      startTLS = ${?REDIS_LETTUCE_START_TLS}
-      startTLS = ${?OTOROSHI_REDIS_LETTUCE_START_TLS}
-      verifyPeers = true
-      verifyPeers = ${?REDIS_LETTUCE_VERIFY_PEERS}
-      verifyPeers = ${?OTOROSHI_REDIS_LETTUCE_VERIFY_PEERS}
-    }
-  }
-}
-
postgresql
-
-
otoroshi {
-  # postrgesql settings. everything possible with the client
-  # WARNING: this is an experimental support and everything might not work as expected !!!
-  pg { 
-    uri = ${?PG_URI}
-    uri = ${?OTOROSHI_PG_URI}
-    uri = ${?POSTGRESQL_ADDON_URI}
-    uri = ${?OTOROSHI_POSTGRESQL_ADDON_URI}
-    poolSize = 20
-    poolSize = ${?PG_POOL_SIZE}
-    poolSize = ${?OTOROSHI_PG_POOL_SIZE}
-    port = 5432
-    port = ${?PG_PORT}
-    port = ${?OTOROSHI_PG_PORT}
-    host = "localhost"
-    host = ${?PG_HOST}
-    host = ${?OTOROSHI_PG_HOST}
-    database = "otoroshi"
-    database = ${?PG_DATABASE}
-    database = ${?OTOROSHI_PG_DATABASE}
-    user = "otoroshi"
-    user = ${?PG_USER}
-    user = ${?OTOROSHI_PG_USER}
-    password = "otoroshi"
-    password = ${?PG_PASSWORD}
-    password = ${?OTOROSHI_PG_PASSWORD}
-    logQueries = ${?PG_DEBUG_QUERIES}
-    logQueries = ${?OTOROSHI_PG_DEBUG_QUERIES}
-    avoidJsonPath = false
-    avoidJsonPath = ${?PG_AVOID_JSON_PATH}
-    avoidJsonPath = ${?OTOROSHI_PG_AVOID_JSON_PATH}
-    optimized = true
-    optimized = ${?PG_OPTIMIZED}
-    optimized = ${?OTOROSHI_PG_OPTIMIZED}
-    connect-timeout = ${?PG_CONNECT_TIMEOUT}
-    connect-timeout = ${?OTOROSHI_PG_CONNECT_TIMEOUT}
-    idle-timeout = ${?PG_IDLE_TIMEOUT}
-    idle-timeout = ${?OTOROSHI_PG_IDLE_TIMEOUT}
-    log-activity = ${?PG_LOG_ACTIVITY}
-    log-activity = ${?OTOROSHI_PG_LOG_ACTIVITY}
-    pipelining-limit = ${?PG_PIPELINING_LIMIT}
-    pipelining-limit = ${?OTOROSHI_PG_PIPELINING_LIMIT}
-    ssl {
-      enabled = false
-      enabled = ${?PG_SSL_ENABLED}
-      enabled = ${?OTOROSHI_PG_SSL_ENABLED}
-      mode = "verify_ca"
-      mode = ${?PG_SSL_MODE}
-      mode = ${?OTOROSHI_PG_SSL_MODE}
-      trusted-certs-path = []
-      trusted-certs = []
-      trusted-cert-path = ${?PG_SSL_TRUSTED_CERT_PATH}
-      trusted-cert-path = ${?OTOROSHI_PG_SSL_TRUSTED_CERT_PATH}
-      trusted-cert = ${?PG_SSL_TRUSTED_CERT}
-      trusted-cert = ${?OTOROSHI_PG_SSL_TRUSTED_CERT}
-      client-certs-path = []
-      client-certs = []
-      client-cert-path = ${?PG_SSL_CLIENT_CERT_PATH}
-      client-cert-path = ${?OTOROSHI_PG_SSL_CLIENT_CERT_PATH}
-      client-cert = ${?PG_SSL_CLIENT_CERT}
-      client-cert = ${?OTOROSHI_PG_SSL_CLIENT_CERT}
-      trust-all = ${?PG_SSL_TRUST_ALL}
-      trust-all = ${?OTOROSHI_PG_SSL_TRUST_ALL}
-    }
-  }
-}
-
cassandra
-
-
otoroshi {
-  cassandra { # cassandra settings. everything possible with the client
-    windowSize = 99
-    windowSize = ${?CASSANDRA_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_CASSANDRA_WINDOW_SIZE}
-    host = "127.0.0.1"
-    host = ${?CASSANDRA_HOST}
-    host = ${?OTOROSHI_CASSANDRA_HOST}
-    port = 9042
-    port = ${?CASSANDRA_PORT}
-    port = ${?OTOROSHI_CASSANDRA_PORT}
-    replicationFactor = 1
-    replicationFactor = ${?CASSANDRA_REPLICATION_FACTOR}
-    replicationFactor = ${?OTOROSHI_CASSANDRA_REPLICATION_FACTOR}
-    replicationOptions = ${?CASSANDRA_REPLICATION_OPTIONS}
-    replicationOptions = ${?OTOROSHI_CASSANDRA_REPLICATION_OPTIONS}
-    durableWrites = true
-    durableWrites = ${?CASSANDRA_DURABLE_WRITES}
-    durableWrites = ${?OTOROSHI_CASSANDRA_DURABLE_WRITES}
-    basic.contact-points = [ ${app.cassandra.host}":"${app.cassandra.port} ]
-    basic.session-name = "otoroshi"
-    basic.session-name = ${?OTOROSHI_CASSANDRA_SESSION_NAME}
-    basic.session-keyspace = ${?OTOROSHI_CASSANDRA_SESSION_KEYSPACE}
-    basic.config-reload-interval = 5 minutes
-    basic.request {
-      timeout = 10 seconds
-      consistency = LOCAL_ONE
-      consistency = ${?OTOROSHI_CASSANDRA_CONSISTENCY}
-      page-size = 5000
-      page-size = ${?OTOROSHI_CASSANDRA_PAGE_SIZE}
-      serial-consistency = SERIAL
-      serial-consistency = ${?OTOROSHI_CASSANDRA_SERIAL_CONSISTENCY}
-      default-idempotence = false
-      default-idempotence = ${?OTOROSHI_CASSANDRA_DEFAULT_IDEMPOTENCE}
-    }
-    basic.load-balancing-policy {
-      class = DefaultLoadBalancingPolicy
-      local-datacenter = datacenter1
-      local-datacenter = ${?OTOROSHI_CASSANDRA_LOCAL_DATACENTER}
-      # filter.class=
-      slow-replica-avoidance = true
-    }
-    basic.cloud {
-      # secure-connect-bundle = /location/of/secure/connect/bundle
-    }
-    basic.application {
-      # name =
-      # version =
-    }
-    basic.graph {
-      # name = your-graph-name
-      traversal-source = "g"
-      # is-system-query = false
-      # read-consistency-level = LOCAL_QUORUM
-      # write-consistency-level = LOCAL_ONE
-      # timeout = 10 seconds
-    }
-    advanced.connection {
-      connect-timeout = 5 seconds
-      init-query-timeout = 500 milliseconds
-      set-keyspace-timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      pool {
-        local {
-          size = 1
-        }
-        remote {
-          size = 1
-        }
-      }
-      max-requests-per-connection = 1024
-      max-orphan-requests = 256
-      warn-on-init-error = true
-    }
-    advanced.reconnect-on-init = false
-    advanced.reconnection-policy {
-      class = ExponentialReconnectionPolicy
-      base-delay = 1 second
-      max-delay = 60 seconds
-    }
-    advanced.retry-policy {
-      class = DefaultRetryPolicy
-    }
-    advanced.speculative-execution-policy {
-      class = NoSpeculativeExecutionPolicy
-      # max-executions = 3
-      # delay = 100 milliseconds
-    }
-    advanced.auth-provider {
-      # class = PlainTextAuthProvider
-      username = ${?CASSANDRA_USERNAME}
-      username = ${?OTOROSHI_CASSANDRA_USERNAME}
-      password = ${?CASSANDRA_PASSWORD}
-      password = ${?OTOROSHI_CASSANDRA_PASSWORD}
-      authorization-id = ${?OTOROSHI_CASSANDRA_AUTHORIZATION_ID}
-      //service = "cassandra"
-      # login-configuration {
-      #   principal = "cassandra@DATASTAX.COM"
-      #   useKeyTab = "true"
-      #   refreshKrb5Config = "true"
-      #   keyTab = "/path/to/keytab/file"
-      # }
-      # sasl-properties {
-      #   javax.security.sasl.qop = "auth-conf"
-      # }
-    }
-    advanced.ssl-engine-factory {
-      # class = DefaultSslEngineFactory
-      # cipher-suites = [ "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" ]
-      # hostname-validation = true
-      # truststore-path = /path/to/client.truststore
-      # truststore-password = password123
-      # keystore-path = /path/to/client.keystore
-      # keystore-password = password123
-    }
-    advanced.timestamp-generator {
-      class = AtomicTimestampGenerator
-      drift-warning {
-        threshold = 1 second
-        interval = 10 seconds
-      }
-      force-java-clock = false
-    }
-    advanced.request-tracker {
-      class = NoopRequestTracker
-      logs {
-        # success.enabled = true
-        slow {
-          # threshold = 1 second
-          # enabled = true
-        }
-        # error.enabled = true
-        # max-query-length = 500
-        # show-values = true
-        # max-value-length = 50
-        # max-values = 50
-        # show-stack-traces = true
-      }
-    }
-    advanced.throttler {
-      class = PassThroughRequestThrottler
-      # max-queue-size = 10000
-      # max-concurrent-requests = 10000
-      # max-requests-per-second = 10000
-      # drain-interval = 10 milliseconds
-    }
-    advanced.node-state-listener.class = NoopNodeStateListener
-    advanced.schema-change-listener.class = NoopSchemaChangeListener
-    advanced.address-translator {
-      class = PassThroughAddressTranslator
-    }
-    advanced.resolve-contact-points = true
-    advanced.protocol {
-      version = V4
-      version = ${?OTOROSHI_CASSANDRA_PROTOCOL_VERSION}
-      compression = lz4
-      compression = ${?OTOROSHI_CASSANDRA_PROTOCOL_COMPRESSION}
-      max-frame-length = 256 MB
-    }
-    advanced.request {
-      warn-if-set-keyspace = false
-      trace {
-        attempts = 5
-        interval = 3 milliseconds
-        consistency = ONE
-      }
-      log-warnings = true
-    }
-    advanced.graph {
-      # sub-protocol = "graphson-2.0"
-      paging-enabled = "AUTO"
-      paging-options {
-        page-size = ${datastax-java-driver.advanced.continuous-paging.page-size}
-        max-pages = ${datastax-java-driver.advanced.continuous-paging.max-pages}
-        max-pages-per-second = ${datastax-java-driver.advanced.continuous-paging.max-pages-per-second}
-        max-enqueued-pages = ${datastax-java-driver.advanced.continuous-paging.max-enqueued-pages}
-      }
-    }
-    advanced.continuous-paging {
-      page-size = ${datastax-java-driver.basic.request.page-size}
-      page-size-in-bytes = false
-      max-pages = 0
-      max-pages-per-second = 0
-      max-enqueued-pages = 4
-      timeout {
-        first-page = 2 seconds
-        other-pages = 1 second
-      }
-    }
-    advanced.monitor-reporting {
-      enabled = true
-    }
-    advanced.metrics {
-      session {
-        enabled = [
-          # bytes-sent,
-          # bytes-received
-          # connected-nodes,
-          # cql-requests,
-          # cql-client-timeouts,
-          # cql-prepared-cache-size,
-          # throttling.delay,
-          # throttling.queue-size,
-          # throttling.errors,
-          # continuous-cql-requests,
-          # graph-requests,
-          # graph-client-timeouts
-        ]
-        cql-requests {
-          highest-latency = 3 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-        throttling.delay {
-          highest-latency = 3 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-        continuous-cql-requests {
-          highest-latency = 120 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-        graph-requests {
-          highest-latency = 12 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-      }
-      node {
-        enabled = [
-          # pool.open-connections,
-          # pool.available-streams,
-          # pool.in-flight,
-          # pool.orphaned-streams,
-          # bytes-sent,
-          # bytes-received,
-          # cql-messages,
-          # errors.request.unsent,
-          # errors.request.aborted,
-          # errors.request.write-timeouts,
-          # errors.request.read-timeouts,
-          # errors.request.unavailables,
-          # errors.request.others,
-          # retries.total,
-          # retries.aborted,
-          # retries.read-timeout,
-          # retries.write-timeout,
-          # retries.unavailable,
-          # retries.other,
-          # ignores.total,
-          # ignores.aborted,
-          # ignores.read-timeout,
-          # ignores.write-timeout,
-          # ignores.unavailable,
-          # ignores.other,
-          # speculative-executions,
-          # errors.connection.init,
-          # errors.connection.auth,
-          # graph-messages,
-        ]
-        cql-messages {
-          highest-latency = 3 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-        graph-messages {
-          highest-latency = 3 seconds
-          significant-digits = 3
-          refresh-interval = 5 minutes
-        }
-      }
-    }
-    advanced.socket {
-      tcp-no-delay = true
-      //keep-alive = false
-      //reuse-address = true
-      //linger-interval = 0
-      //receive-buffer-size = 65535
-      //send-buffer-size = 65535
-    }
-    advanced.heartbeat {
-      interval = 30 seconds
-      timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-    }
-    advanced.metadata {
-      topology-event-debouncer {
-        window = 1 second
-        max-events = 20
-      }
-      schema {
-        enabled = true
-        # refreshed-keyspaces = [ "ks1", "ks2" ]
-        request-timeout = ${datastax-java-driver.basic.request.timeout}
-        request-page-size = ${datastax-java-driver.basic.request.page-size}
-        debouncer {
-          window = 1 second
-          max-events = 20
-        }
-      }
-      token-map.enabled = true
-    }
-    advanced.control-connection {
-      timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      schema-agreement {
-        interval = 200 milliseconds
-        timeout = 10 seconds
-        warn-on-failure = true
-      }
-    }
-    advanced.prepared-statements {
-      prepare-on-all-nodes = true
-      reprepare-on-up {
-        enabled = true
-        check-system-table = false
-        max-statements = 0
-        max-parallelism = 100
-        timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      }
-    }
-    advanced.netty {
-      daemon = false
-      io-group {
-        size = 0
-        shutdown {quiet-period = 2, timeout = 15, unit = SECONDS}
-      }
-      admin-group {
-        size = 2
-        shutdown {quiet-period = 2, timeout = 15, unit = SECONDS}
-      }
-      timer {
-        tick-duration = 100 milliseconds
-        ticks-per-wheel = 2048
-      }
-    }
-    advanced.coalescer {
-      max-runs-with-no-work = 5
-      reschedule-interval = 10 microseconds
-    }
-  }
-}
-
-

Setup your hosts before running

-

By default, Otoroshi starts with domain oto.tools that automatically targets 127.0.0.1 with no changes to your /etc/hosts file. Of course you can change the domain value, you have to add the values in your /etc/hosts file according to the setting you put in Otoroshi configuration or define the right ip address at the DNS provider level

-
    -
  • otoroshi.domain => mydomain.org
  • -
  • otoroshi.backoffice.subdomain => otoroshi
  • -
  • otoroshi.privateapps.subdomain => privateapps
  • -
  • otoroshi.adminapi.exposedSubdomain => otoroshi-api
  • -
  • otoroshi.adminapi.targetSubdomain => otoroshi-admin-internal-api
  • -
-

for instance if you want to change the default domain and use something like otoroshi.mydomain.org, then start otoroshi like

-
java -Dotoroshi.domain=mydomain.org -jar otoroshi.jar
-
Warning
-

Otoroshi cannot be accessed using http://127.0.0.1:8080 or http://localhost:8080 because Otoroshi uses Otoroshi to serve it’s own UI and API. When otoroshi starts with an empty database, it will create a service descriptor for that using otoroshi.domain and the settings listed on this page and in the here that serve Otoroshi API and UI on http://otoroshi-api.${otoroshi.domain} and http://otoroshi.${otoroshi.domain}. Once the descriptor is saved in database, if you want to change otoroshi.domain, you’ll have to edit the descriptor in the database or restart Otoroshi with an empty database.

Warning
-

if your otoroshi instance runs behind a reverse proxy (L4 / L7) or inside a docker container where exposed ports (that you will use to access otoroshi) are not the same that the ones configured in otoroshi (http.port and https.port), you’ll have to configure otoroshi exposed port to avoid bad redirection URLs when using authentication modules and other otoroshi tools. To do that, just set the values of the exposed ports in otoroshi.exposed-ports.http = $theExposedHttpPort (OTOROSHI_EXPOSED_PORTS_HTTP) and otoroshi.exposed-ports.https = $theExposedHttpsPort (OTOROSHI_EXPOSED_PORTS_HTTPS)

-

Setup your configuration file

-

There is a lot of things you can configure in Otoroshi. By default, Otoroshi provides a configuration that should be enough for testing purpose. But you’ll likely need to update this configuration when you’ll need to move into production.

-

In this page, any configuration property can be set at runtime using a -D flag when launching Otoroshi like

-
java -Dhttp.port=8080 -jar otoroshi.jar
-
-

or

-
./bin/otoroshi -Dhttp.port=8080 
-
-

if you want to define your own config file and use it on an otoroshi instance, use the following flag

-
java -Dconfig.file=/path/to/otoroshi.conf -jar otoroshi.jar
-
-

Example of a custom. configuration file

-
include "application.conf"
-
-http.port = 8080
-
-app {
-  storage = "inmemory"
-  importFrom = "./my-state.json"
-  env = "prod"
-  domain = "oto.tools"
-  rootScheme = "http"
-  snowflake {
-    seed = 0
-  }
-  events {
-    maxSize = 1000
-  }
-  backoffice {
-    subdomain = "otoroshi"
-    session {
-      exp = 86400000
-    }
-  }
-  privateapps {
-    subdomain = "privateapps"
-    session {
-      exp = 86400000
-    }
-  }
-  adminapi {
-    targetSubdomain = "otoroshi-admin-internal-api"
-    exposedSubdomain = "otoroshi-api"
-    defaultValues {
-      backOfficeGroupId = "admin-api-group"
-      backOfficeApiKeyClientId = "admin-api-apikey-id"
-      backOfficeApiKeyClientSecret = "admin-api-apikey-secret"
-      backOfficeServiceId = "admin-api-service"
-    }
-  }
-  claim {
-    sharedKey = "mysecret"
-  }
-  filedb {
-    path = "./filedb/state.ndjson"
-  }
-}
-
-play.http {
-  session {
-    secure = false
-    httpOnly = true
-    maxAge = 2592000000
-    domain = ".oto.tools"
-    cookieName = "oto-sess"
-  }
-}
-
-

Reference configuration

-

app { - storage = "inmemory" # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg - storage = ${?APP_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg - storage = ${?OTOROSHI_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg - storageRoot = "otoroshi" # the prefix used for storage keys - storageRoot = ${?APP_STORAGE_ROOT} # the prefix used for storage keys - storageRoot = ${?OTOROSHI_STORAGE_ROOT} # the prefix used for storage keys - eventsName = "otoroshi" # the name of the event producer - eventsName = ${?APP_EVENTS_NAME} # the name of the event producer - eventsName = ${?OTOROSHI_EVENTS_NAME} # the name of the event producer - importFrom = ${?APP_IMPORT_FROM} # file path to import otoroshi initial configuration - importFrom = ${?OTOROSHI_IMPORT_FROM} # file path to import otoroshi initial configuration - env = "prod" # env name, should always be prod except in dev mode - env = ${?APP_ENV} # env name, should always be prod except in dev mode - env = ${?OTOROSHI_ENV} # env name, should always be prod except in dev mode - liveJs = false # enabled live JS loading for dev mode - domain = "oto.tools" # default domain for basic otoroshi services - domain = ${?APP_DOMAIN} # default domain for basic otoroshi services - domain = ${?OTOROSHI_DOMAIN} # default domain for basic otoroshi services - commitId = "HEAD" - commitId = ${?COMMIT_ID} - commitId = ${?OTOROSHI_COMMIT_ID} - rootScheme = "http" # default root scheme when composing urls - rootScheme = ${?APP_ROOT_SCHEME} # default root scheme when composing urls - rootScheme = ${?OTOROSHI_ROOT_SCHEME} # default root scheme when composing urls - throttlingWindow = 10 # the number of second used to compute throttling number - throttlingWindow = ${?THROTTLING_WINDOW} # the number of second used to compute throttling number - throttlingWindow = ${?OTOROSHI_THROTTLING_WINDOW} # the number of second used to compute throttling number - checkForUpdates = true # enable automatic version update checks - checkForUpdates = ${?CHECK_FOR_UPDATES} # enable automatic version update checks - checkForUpdates = ${?OTOROSHI_CHECK_FOR_UPDATES} # enable automatic version update checks - overheadThreshold = 500.0 # the value threshold (in milliseconds) used to send HighOverheadAlert - overheadThreshold = ${?OVERHEAD_THRESHOLD} # the value threshold (in milliseconds) used to send HighOverheadAlert - overheadThreshold = ${?OTOROSHI_OVERHEAD_THRESHOLD} # the value threshold (in milliseconds) used to send HighOverheadAlert - adminLogin = ${?OTOROSHI_INITIAL_ADMIN_LOGIN} # the initial admin login - adminPassword = ${?OTOROSHI_INITIAL_ADMIN_PASSWORD} # the initial admin password - initialCustomization = ${?OTOROSHI_INITIAL_CUSTOMIZATION} # otoroshi inital configuration that will be merged with a new confguration. Shaped like an otoroshi export - boot { - globalWait = true # should we wait until everything is setup to accept http requests - globalWait = ${?OTOROSHI_BOOT_GLOBAL_WAIT} # should we wait until everything is setup to accept http requests - globalWaitTimeout = 60000 # max wait before accepting requests - globalWaitTimeout = ${?OTOROSHI_BOOT_GLOBAL_WAIT_TIMEOUT} # max wait before accepting requests - - waitForPluginsSearch = true # should we wait for classpath plugins search before accepting http requests - waitForPluginsSearch = ${?OTOROSHI_BOOT_WAIT_FOR_PLUGINS_SEARCH} # should we wait for classpath plugins search before accepting http requests - waitForPluginsSearchTimeout = 20000 # max wait for classpath plugins search before accepting http requests - waitForPluginsSearchTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_PLUGINS_SEARCH_TIMEOUT} # max wait for classpath plugins search before accepting http requests - - waitForScriptsCompilation = true # should we wait for plugins compilation before accepting http requests - waitForScriptsCompilation = ${?OTOROSHI_BOOT_WAIT_FOR_SCRIPTS_COMPILATION} # should we wait for plugins compilation before accepting http requests - waitForScriptsCompilationTimeout = 30000 # max wait for plugins compilation before accepting http requests - waitForScriptsCompilationTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_SCRIPTS_COMPILATION_TIMEOUT} # max wait for plugins compilation before accepting http requests - - waitForTlsInit = true # should we wait for first TLS context initialization before accepting http requests - waitForTlsInit = ${?OTOROSHI_BOOT_WAIT_FOR_TLS_INIT} # should we wait for first TLS context initialization before accepting http requests - waitForTlsInitTimeout = 10000 # max wait for first TLS context initialization before accepting http requests - waitForTlsInitTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_TLS_INIT_TIMEOUT} # max wait for first TLS context initialization before accepting http requests - - waitForFirstClusterFetch = true # should we wait for first cluster initialization before accepting http requests - waitForFirstClusterFetch = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_FETCH} # should we wait for first cluster initialization before accepting http requests - waitForFirstClusterFetchTimeout = 10000 # max wait for first cluster initialization before accepting http requests - waitForFirstClusterFetchTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_TIMEOUT} # max wait for first cluster initialization before accepting http requests - - waitForFirstClusterStateCache = true # should we wait for first cluster initialization before accepting http requests - waitForFirstClusterStateCache = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_STATE_CACHE} # should we wait for first cluster initialization before accepting http requests - waitForFirstClusterStateCacheTimeout = 10000 # max wait for first cluster initialization before accepting http requests - waitForFirstClusterStateCacheTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_STATE_CACHE_TIMEOUT} # max wait for first cluster initialization before accepting http requests - } - instance { - instanceId = ${?OTOROSHI_INSTANCE_ID} # the instance id - number = 0 # the instance number. Can be found in otoroshi events - number = ${?OTOROSHI_INSTANCE_NUMBER} # the instance number. Can be found in otoroshi events - number = ${?INSTANCE_NUMBER} # the instance number. Can be found in otoroshi events - name = "otoroshi" # instance name - name = ${?OTOROSHI_INSTANCE_NAME} # instance name - zone = "local" # instance zone (optional) - zone = ${?OTOROSHI_INSTANCE_ZONE} # instance zone (optional) - region = "local" # instance region (optional) - region = ${?OTOROSHI_INSTANCE_REGION} # instance region (optional) - dc = "local" # instance dc (optional) - dc = ${?OTOROSHI_INSTANCE_DATACENTER} # instance dc (optional) - provider = "local" # instance provider (optional) - provider = ${?OTOROSHI_INSTANCE_PROVIDER} # instance provider (optional) - rack = "local" # instance rack (optional) - rack = ${?OTOROSHI_INSTANCE_RACK} # instance rack (optional) - title = ${?OTOROSHI_INSTANCE_TITLE} # the title displayed in UI top left - } - } - health { - limit = 1000 # the value threshold (in milliseconds) used to indicate if an otoroshi instance is healthy or not - limit = ${?HEALTH_LIMIT} # the value threshold (in milliseconds) used to indicate if an otoroshi instance is healthy or not - limit = ${?OTOROSHI_HEALTH_LIMIT} # the value threshold (in milliseconds) used to indicate if an otoroshi instance is healthy or not - accessKey = ${?HEALTH_ACCESS_KEY} # the key to access /health edpoint - accessKey = ${?OTOROSHI_HEALTH_ACCESS_KEY} # the key to access /health edpoint - } - snowflake { - seed = 0 # the seed number used to generate unique ids. Should be different for every instances - seed = ${?INSTANCE_NUMBER} # the seed number used to generate unique ids. Should be different for every instances - seed = ${?OTOROSHI_INSTANCE_NUMBER} # the seed number used to generate unique ids. Should be different for every instances - seed = ${?SNOWFLAKE_SEED} # the seed number used to generate unique ids. Should be different for every instances - seed = ${?OTOROSHI_SNOWFLAKE_SEED} # the seed number used to generate unique ids. Should be different for every instances - } - events { - maxSize = 1000 # the amount of event kept in the datastore - maxSize = ${?MAX_EVENTS_SIZE} # the amount of event kept in the datastore - maxSize = ${?OTOROSHI_MAX_EVENTS_SIZE} # the amount of event kept in the datastore - } - exposed-ports { - http = ${?APP_EXPOSED_PORTS_HTTP} # the exposed http port for otoroshi (when in a container or behind a proxy) - http = ${?OTOROSHI_EXPOSED_PORTS_HTTP} # the exposed http port for otoroshi (when in a container or behind a proxy) - https = ${?APP_EXPOSED_PORTS_HTTPS} # the exposed https port for otoroshi (when in a container or behind a proxy - https = ${?OTOROSHI_EXPOSED_PORTS_HTTPS} # the exposed https port for otoroshi (when in a container or behind a proxy - } - backoffice { - exposed = true # expose the backoffice ui - exposed = ${?APP_BACKOFFICE_EXPOSED} # expose the backoffice ui - exposed = ${?OTOROSHI_BACKOFFICE_EXPOSED} # expose the backoffice ui - subdomain = "otoroshi" # the backoffice subdomain - subdomain = ${?APP_BACKOFFICE_SUBDOMAIN} # the backoffice subdomain - subdomain = ${?OTOROSHI_BACKOFFICE_SUBDOMAIN} # the backoffice subdomain - domains = [] # the backoffice domains - domainsStr = ${?APP_BACKOFFICE_DOMAINS} # the backoffice domains - domainsStr = ${?OTOROSHI_BACKOFFICE_DOMAINS} # the backoffice domains - session { - exp = 86400000 # the backoffice cookie expiration - exp = ${?APP_BACKOFFICE_SESSION_EXP} # the backoffice cookie expiration - exp = ${?OTOROSHI_BACKOFFICE_SESSION_EXP} # the backoffice cookie expiration - } - } - privateapps { - subdomain = "privateapps" # privateapps (proxy sso) domain - subdomain = ${?APP_PRIVATEAPPS_SUBDOMAIN} # privateapps (proxy sso) domain - subdomain = ${?OTOROSHI_PRIVATEAPPS_SUBDOMAIN} # privateapps (proxy sso) domain - domains = [] - domainsStr = ${?APP_PRIVATEAPPS_DOMAINS} - domainsStr = ${?OTOROSHI_PRIVATEAPPS_DOMAINS} - session { - exp = 86400000 # the privateapps cookie expiration - exp = ${?APP_PRIVATEAPPS_SESSION_EXP} # the privateapps cookie expiration - exp = ${?OTOROSHI_PRIVATEAPPS_SESSION_EXP} # the privateapps cookie expiration - } - } - adminapi { - exposed = true # expose the admin api - exposed = ${?ADMIN_API_EXPOSED} # expose the admin api - exposed = ${?OTOROSHI_ADMIN_API_EXPOSED} # expose the admin api - targetSubdomain = "otoroshi-admin-internal-api" # admin api target subdomain as targeted by otoroshi service - targetSubdomain = ${?ADMIN_API_TARGET_SUBDOMAIN} # admin api target subdomain as targeted by otoroshi service - targetSubdomain = ${?OTOROSHI_ADMIN_API_TARGET_SUBDOMAIN} # admin api target subdomain as targeted by otoroshi service - exposedSubdomain = "otoroshi-api" # admin api exposed subdomain as exposed by otoroshi service - exposedSubdomain = ${?ADMIN_API_EXPOSED_SUBDOMAIN} # admin api exposed subdomain as exposed by otoroshi service - exposedSubdomain = ${?OTOROSHI_ADMIN_API_EXPOSED_SUBDOMAIN} # admin api exposed subdomain as exposed by otoroshi service - additionalExposedDomain = ${?ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN} # admin api additional exposed subdomain as exposed by otoroshi service - additionalExposedDomain = ${?OTOROSHI_ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN} # admin api additional exposed subdomain as exposed by otoroshi service - domains = [] - domainsStr = ${?ADMIN_API_DOMAINS} - domainsStr = ${?OTOROSHI_ADMIN_API_DOMAINS} - exposedDomains = [] - exposedDomainsStr = ${?ADMIN_API_EXPOSED_DOMAINS} - exposedDomainsStr = ${?OTOROSHI_ADMIN_API_EXPOSED_DOMAINS} - defaultValues { - backOfficeGroupId = "admin-api-group" # default value for admin api service group - backOfficeGroupId = ${?ADMIN_API_GROUP} # default value for admin api service group - backOfficeGroupId = ${?OTOROSHI_ADMIN_API_GROUP} # default value for admin api service group - backOfficeApiKeyClientId = "admin-api-apikey-id" # default value for admin api apikey id - backOfficeApiKeyClientId = ${?ADMIN_API_CLIENT_ID} # default value for admin api apikey id - backOfficeApiKeyClientId = ${?OTOROSHI_ADMIN_API_CLIENT_ID} # default value for admin api apikey id - backOfficeApiKeyClientSecret = "admin-api-apikey-secret" # default value for admin api apikey secret - backOfficeApiKeyClientSecret = ${?otoroshi.admin-api-secret} # default value for admin api apikey secret - backOfficeApiKeyClientSecret = ${?OTOROSHI_otoroshi.admin-api-secret} # default value for admin api apikey secret - backOfficeApiKeyClientSecret = ${?ADMIN_API_CLIENT_SECRET} # default value for admin api apikey secret - backOfficeApiKeyClientSecret = ${?OTOROSHI_ADMIN_API_CLIENT_SECRET} # default value for admin api apikey secret - backOfficeServiceId = "admin-api-service" # default value for admin api service id - backOfficeServiceId = ${?ADMIN_API_SERVICE_ID} # default value for admin api service id - backOfficeServiceId = ${?OTOROSHI_ADMIN_API_SERVICE_ID} # default value for admin api service id - } - proxy { - https = false # backoffice proxy admin api over https - https = ${?ADMIN_API_HTTPS} # backoffice proxy admin api over https - https = ${?OTOROSHI_ADMIN_API_HTTPS} # backoffice proxy admin api over https - local = true # backoffice proxy admin api on localhost - local = ${?ADMIN_API_LOCAL} # backoffice proxy admin api on localhost - local = ${?OTOROSHI_ADMIN_API_LOCAL} # backoffice proxy admin api on localhost - } - } - claim { - sharedKey = "secret" # the default secret used to sign otoroshi exchange protocol tokens - sharedKey = ${?CLAIM_SHAREDKEY} # the default secret used to sign otoroshi exchange protocol tokens - sharedKey = ${?OTOROSHI_CLAIM_SHAREDKEY} # the default secret used to sign otoroshi exchange protocol tokens - } - webhooks { - } - redis { # configuration to fetch/store otoroshi state from a redis datastore using rediscala - host = "localhost" - host = ${?REDIS_HOST} - host = ${?OTOROSHI_REDIS_HOST} - port = 6379 - port = ${?REDIS_PORT} - port = ${?OTOROSHI_REDIS_PORT} - password = ${?REDIS_PASSWORD} - password = ${?OTOROSHI_REDIS_PASSWORD} - windowSize = 99 - windowSize = ${?REDIS_WINDOW_SIZE} - windowSize = ${?OTOROSHI_REDIS_WINDOW_SIZE} - slaves = [] - slavesStr = ${?REDIS_SLAVES} - slavesStr = ${?OTOROSHI_REDIS_SLAVES} - slavesStr = ${?REDIS_MEMBERS} - slavesStr = ${?OTOROSHI_REDIS_MEMBERS} - useScan = false - useScan = ${?REDIS_USE_SCAN} - useScan = ${?OTOROSHI_REDIS_USE_SCAN} - - pool { - members = [] - members = ${?REDIS_POOL_MEMBERS} - members = ${?OTOROSHI_REDIS_POOL_MEMBERS} - } - - mpool { - members = [] - membersStr = ${?REDIS_MPOOL_MEMBERS} - membersStr = ${?OTOROSHI_REDIS_MPOOL_MEMBERS} - } - - lf { - master { - host = ${?REDIS_LF_HOST} - host = ${?OTOROSHI_REDIS_LF_HOST} - port = ${?REDIS_LF_PORT} - port = ${?OTOROSHI_REDIS_LF_PORT} - password = ${?REDIS_LF_PASSWORD} - password = ${?OTOROSHI_REDIS_LF_PASSWORD} - } - slaves = [] - slavesStr = ${?REDIS_LF_SLAVES} - slavesStr = ${?OTOROSHI_REDIS_LF_SLAVES} - slavesStr = ${?REDIS_LF_MEMBERS} - slavesStr = ${?OTOROSHI_REDIS_LF_MEMBERS} - } - - sentinels { - master = ${?REDIS_SENTINELS_MASTER} - master = ${?OTOROSHI_REDIS_SENTINELS_MASTER} - password = ${?REDIS_SENTINELS_PASSWORD} - password = ${?OTOROSHI_REDIS_SENTINELS_PASSWORD} - db = ${?REDIS_SENTINELS_DB} - db = ${?OTOROSHI_REDIS_SENTINELS_DB} - name = ${?REDIS_SENTINELS_NAME} - name = ${?OTOROSHI_REDIS_SENTINELS_NAME} - members = [] - membersStr = ${?REDIS_SENTINELS_MEMBERS} - membersStr = ${?OTOROSHI_REDIS_SENTINELS_MEMBERS} - - lf { - master = ${?REDIS_SENTINELS_LF_MASTER} - master = ${?OTOROSHI_REDIS_SENTINELS_LF_MASTER} - members = [] - membersStr = ${?REDIS_SENTINELS_LF_MEMBERS} - membersStr = ${?OTOROSHI_REDIS_SENTINELS_LF_MEMBERS} - } - } - - cluster { - members = [] - membersStr = ${?REDIS_CLUSTER_MEMBERS} - membersStr = ${?OTOROSHI_REDIS_CLUSTER_MEMBERS} - } - - lettuce { # configuration to fetch/store otoroshi state from a redis datastore using the lettuce driver (the next default one) - connection = "default" - connection = ${?REDIS_LETTUCE_CONNECTION} - connection = ${?OTOROSHI_REDIS_LETTUCE_CONNECTION} - uri = ${?REDIS_LETTUCE_URI} - uri = ${?OTOROSHI_REDIS_LETTUCE_URI} - uri = ${?REDIS_URL} - uri = ${?OTOROSHI_REDIS_URL} - uris = [] - urisStr = ${?REDIS_LETTUCE_URIS} - urisStr = ${?OTOROSHI_REDIS_LETTUCE_URIS} - readFrom = "MASTER_PREFERRED" - readFrom = ${?REDIS_LETTUCE_READ_FROM} - readFrom = ${?OTOROSHI_REDIS_LETTUCE_READ_FROM} - startTLS = false - startTLS = ${?REDIS_LETTUCE_START_TLS} - startTLS = ${?OTOROSHI_REDIS_LETTUCE_START_TLS} - verifyPeers = true - verifyPeers = ${?REDIS_LETTUCE_VERIFY_PEERS} - verifyPeers = ${?OTOROSHI_REDIS_LETTUCE_VERIFY_PEERS} - } - } - inmemory { # configuration to fetch/store otoroshi state in memory - windowSize = 99 - windowSize = ${?INMEMORY_WINDOW_SIZE} - windowSize = ${?OTOROSHI_INMEMORY_WINDOW_SIZE} - experimental = false - experimental = ${?INMEMORY_EXPERIMENTAL_STORE} - experimental = ${?OTOROSHI_INMEMORY_EXPERIMENTAL_STORE} - optimized = false - optimized = ${?INMEMORY_OPTIMIZED} - optimized = ${?OTOROSHI_INMEMORY_OPTIMIZED} - modern = false - modern = ${?INMEMORY_MODERN} - modern = ${?OTOROSHI_INMEMORY_MODERN} - } - filedb { # configuration to fetch/store otoroshi state from a file - windowSize = 99 - windowSize = ${?FILEDB_WINDOW_SIZE} - windowSize = ${?OTOROSHI_FILEDB_WINDOW_SIZE} - path = "./filedb/state.ndjson" - path = ${?FILEDB_PATH} - path = ${?OTOROSHI_FILEDB_PATH} - } - httpdb { # configuration to fetch/store otoroshi state from an http endpoint - url = "http://127.0.0.1:8888/worker-0/state.json" - headers = {} - timeout = 10000 - pollEvery = 10000 - } - s3db { # configuration to fetch/store otoroshi state from a S3 bucket - bucket = "otoroshi-states" - bucket = ${?OTOROSHI_DB_S3_BUCKET} - endpoint = "https://otoroshi-states.foo.bar" - endpoint = ${?OTOROSHI_DB_S3_ENDPOINT} - region = "eu-west-1" - region = ${?OTOROSHI_DB_S3_REGION} - access = "secret" - access = ${?OTOROSHI_DB_S3_ACCESS} - secret = "secret" - secret = ${?OTOROSHI_DB_S3_SECRET} - key = "/otoroshi/states/state" - key = ${?OTOROSHI_DB_S3_KEY} - chunkSize = 8388608 - chunkSize = ${?OTOROSHI_DB_S3_CHUNK_SIZE} - v4auth = true - v4auth = ${?OTOROSHI_DB_S3_V4_AUTH} - writeEvery = 60000 # write interval - writeEvery = ${?OTOROSHI_DB_S3_WRITE_EVERY} # write interval - acl = "Private" - acl = ${?OTOROSHI_DB_S3_ACL} - } - pg { # postrgesql settings. everything possible with the client - uri = ${?PG_URI} - uri = ${?OTOROSHI_PG_URI} - uri = ${?POSTGRESQL_ADDON_URI} - uri = ${?OTOROSHI_POSTGRESQL_ADDON_URI} - poolSize = 20 - poolSize = ${?PG_POOL_SIZE} - poolSize = ${?OTOROSHI_PG_POOL_SIZE} - port = 5432 - port = ${?PG_PORT} - port = ${?OTOROSHI_PG_PORT} - host = "localhost" - host = ${?PG_HOST} - host = ${?OTOROSHI_PG_HOST} - database = "otoroshi" - database = ${?PG_DATABASE} - database = ${?OTOROSHI_PG_DATABASE} - user = "otoroshi" - user = ${?PG_USER} - user = ${?OTOROSHI_PG_USER} - password = "otoroshi" - password = ${?PG_PASSWORD} - password = ${?OTOROSHI_PG_PASSWORD} - logQueries = ${?PG_DEBUG_QUERIES} - logQueries = ${?OTOROSHI_PG_DEBUG_QUERIES} - avoidJsonPath = false - avoidJsonPath = ${?PG_AVOID_JSON_PATH} - avoidJsonPath = ${?OTOROSHI_PG_AVOID_JSON_PATH} - optimized = true - optimized = ${?PG_OPTIMIZED} - optimized = ${?OTOROSHI_PG_OPTIMIZED} - connect-timeout = ${?PG_CONNECT_TIMEOUT} - connect-timeout = ${?OTOROSHI_PG_CONNECT_TIMEOUT} - idle-timeout = ${?PG_IDLE_TIMEOUT} - idle-timeout = ${?OTOROSHI_PG_IDLE_TIMEOUT} - log-activity = ${?PG_LOG_ACTIVITY} - log-activity = ${?OTOROSHI_PG_LOG_ACTIVITY} - pipelining-limit = ${?PG_PIPELINING_LIMIT} - pipelining-limit = ${?OTOROSHI_PG_PIPELINING_LIMIT} - ssl { - enabled = false - enabled = ${?PG_SSL_ENABLED} - enabled = ${?OTOROSHI_PG_SSL_ENABLED} - mode = "verify_ca" - mode = ${?PG_SSL_MODE} - mode = ${?OTOROSHI_PG_SSL_MODE} - trusted-certs-path = [] - trusted-certs = [] - trusted-cert-path = ${?PG_SSL_TRUSTED_CERT_PATH} - trusted-cert-path = ${?OTOROSHI_PG_SSL_TRUSTED_CERT_PATH} - trusted-cert = ${?PG_SSL_TRUSTED_CERT} - trusted-cert = ${?OTOROSHI_PG_SSL_TRUSTED_CERT} - client-certs-path = [] - client-certs = [] - client-cert-path = ${?PG_SSL_CLIENT_CERT_PATH} - client-cert-path = ${?OTOROSHI_PG_SSL_CLIENT_CERT_PATH} - client-cert = ${?PG_SSL_CLIENT_CERT} - client-cert = ${?OTOROSHI_PG_SSL_CLIENT_CERT} - trust-all = ${?PG_SSL_TRUST_ALL} - trust-all = ${?OTOROSHI_PG_SSL_TRUST_ALL} - } - } - cassandra { # cassandra settings. everything possible with the client - windowSize = 99 - windowSize = ${?CASSANDRA_WINDOW_SIZE} - windowSize = ${?OTOROSHI_CASSANDRA_WINDOW_SIZE} - host = "127.0.0.1" - host = ${?CASSANDRA_HOST} - host = ${?OTOROSHI_CASSANDRA_HOST} - port = 9042 - port = ${?CASSANDRA_PORT} - port = ${?OTOROSHI_CASSANDRA_PORT} - replicationFactor = 1 - replicationFactor = ${?CASSANDRA_REPLICATION_FACTOR} - replicationFactor = ${?OTOROSHI_CASSANDRA_REPLICATION_FACTOR} - replicationOptions = ${?CASSANDRA_REPLICATION_OPTIONS} - replicationOptions = ${?OTOROSHI_CASSANDRA_REPLICATION_OPTIONS} - durableWrites = true - durableWrites = ${?CASSANDRA_DURABLE_WRITES} - durableWrites = ${?OTOROSHI_CASSANDRA_DURABLE_WRITES} - basic.contact-points = [ ${app.cassandra.host}":"${app.cassandra.port} ] - basic.session-name = "otoroshi" - basic.session-name = ${?OTOROSHI_CASSANDRA_SESSION_NAME} - basic.session-keyspace = ${?OTOROSHI_CASSANDRA_SESSION_KEYSPACE} - basic.config-reload-interval = 5 minutes - basic.request { - timeout = 10 seconds - consistency = LOCAL_ONE - consistency = ${?OTOROSHI_CASSANDRA_CONSISTENCY} - page-size = 5000 - page-size = ${?OTOROSHI_CASSANDRA_PAGE_SIZE} - serial-consistency = SERIAL - serial-consistency = ${?OTOROSHI_CASSANDRA_SERIAL_CONSISTENCY} - default-idempotence = false - default-idempotence = ${?OTOROSHI_CASSANDRA_DEFAULT_IDEMPOTENCE} - } - basic.load-balancing-policy { - class = DefaultLoadBalancingPolicy - local-datacenter = datacenter1 - local-datacenter = ${?OTOROSHI_CASSANDRA_LOCAL_DATACENTER} - # filter.class= - slow-replica-avoidance = true - } - basic.cloud { - # secure-connect-bundle = /location/of/secure/connect/bundle - } - basic.application { - # name = - # version = - } - basic.graph { - # name = your-graph-name - traversal-source = "g" - # is-system-query = false - # read-consistency-level = LOCAL_QUORUM - # write-consistency-level = LOCAL_ONE - # timeout = 10 seconds - } - advanced.connection { - connect-timeout = 5 seconds - init-query-timeout = 500 milliseconds - set-keyspace-timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} - pool { - local { - size = 1 - } - remote { - size = 1 - } - } - max-requests-per-connection = 1024 - max-orphan-requests = 256 - warn-on-init-error = true - } - advanced.reconnect-on-init = false - advanced.reconnection-policy { - class = ExponentialReconnectionPolicy - base-delay = 1 second - max-delay = 60 seconds - } - advanced.retry-policy { - class = DefaultRetryPolicy - } - advanced.speculative-execution-policy { - class = NoSpeculativeExecutionPolicy - # max-executions = 3 - # delay = 100 milliseconds - } - advanced.auth-provider { - # class = PlainTextAuthProvider - username = ${?CASSANDRA_USERNAME} - username = ${?OTOROSHI_CASSANDRA_USERNAME} - password = ${?CASSANDRA_PASSWORD} - password = ${?OTOROSHI_CASSANDRA_PASSWORD} - authorization-id = ${?OTOROSHI_CASSANDRA_AUTHORIZATION_ID} - //service = "cassandra" - # login-configuration { - # principal = "cassandra@DATASTAX.COM" - # useKeyTab = "true" - # refreshKrb5Config = "true" - # keyTab = "/path/to/keytab/file" - # } - # sasl-properties { - # javax.security.sasl.qop = "auth-conf" - # } - } - advanced.ssl-engine-factory { - # class = DefaultSslEngineFactory - # cipher-suites = [ "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" ] - # hostname-validation = true - # truststore-path = /path/to/client.truststore - # truststore-password = password123 - # keystore-path = /path/to/client.keystore - # keystore-password = password123 - } - advanced.timestamp-generator { - class = AtomicTimestampGenerator - drift-warning { - threshold = 1 second - interval = 10 seconds - } - force-java-clock = false - } - advanced.request-tracker { - class = NoopRequestTracker - logs { - # success.enabled = true - slow { - # threshold = 1 second - # enabled = true - } - # error.enabled = true - # max-query-length = 500 - # show-values = true - # max-value-length = 50 - # max-values = 50 - # show-stack-traces = true - } - } - advanced.throttler { - class = PassThroughRequestThrottler - # max-queue-size = 10000 - # max-concurrent-requests = 10000 - # max-requests-per-second = 10000 - # drain-interval = 10 milliseconds - } - advanced.node-state-listener.class = NoopNodeStateListener - advanced.schema-change-listener.class = NoopSchemaChangeListener - advanced.address-translator { - class = PassThroughAddressTranslator - } - advanced.resolve-contact-points = true - advanced.protocol { - version = V4 - version = ${?OTOROSHI_CASSANDRA_PROTOCOL_VERSION} - compression = lz4 - compression = ${?OTOROSHI_CASSANDRA_PROTOCOL_COMPRESSION} - max-frame-length = 256 MB - } - advanced.request { - warn-if-set-keyspace = false - trace { - attempts = 5 - interval = 3 milliseconds - consistency = ONE - } - log-warnings = true - } - advanced.graph { - # sub-protocol = "graphson-2.0" - paging-enabled = "AUTO" - paging-options { - page-size = ${datastax-java-driver.advanced.continuous-paging.page-size} - max-pages = ${datastax-java-driver.advanced.continuous-paging.max-pages} - max-pages-per-second = ${datastax-java-driver.advanced.continuous-paging.max-pages-per-second} - max-enqueued-pages = ${datastax-java-driver.advanced.continuous-paging.max-enqueued-pages} - } - } - advanced.continuous-paging { - page-size = ${datastax-java-driver.basic.request.page-size} - page-size-in-bytes = false - max-pages = 0 - max-pages-per-second = 0 - max-enqueued-pages = 4 - timeout { - first-page = 2 seconds - other-pages = 1 second - } - } - advanced.monitor-reporting { - enabled = true - } - advanced.metrics { - session { - enabled = [ - # bytes-sent, - # bytes-received - # connected-nodes, - # cql-requests, - # cql-client-timeouts, - # cql-prepared-cache-size, - # throttling.delay, - # throttling.queue-size, - # throttling.errors, - # continuous-cql-requests, - # graph-requests, - # graph-client-timeouts - ] - cql-requests { - highest-latency = 3 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - throttling.delay { - highest-latency = 3 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - continuous-cql-requests { - highest-latency = 120 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - graph-requests { - highest-latency = 12 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - } - node { - enabled = [ - # pool.open-connections, - # pool.available-streams, - # pool.in-flight, - # pool.orphaned-streams, - # bytes-sent, - # bytes-received, - # cql-messages, - # errors.request.unsent, - # errors.request.aborted, - # errors.request.write-timeouts, - # errors.request.read-timeouts, - # errors.request.unavailables, - # errors.request.others, - # retries.total, - # retries.aborted, - # retries.read-timeout, - # retries.write-timeout, - # retries.unavailable, - # retries.other, - # ignores.total, - # ignores.aborted, - # ignores.read-timeout, - # ignores.write-timeout, - # ignores.unavailable, - # ignores.other, - # speculative-executions, - # errors.connection.init, - # errors.connection.auth, - # graph-messages, - ] - cql-messages { - highest-latency = 3 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - graph-messages { - highest-latency = 3 seconds - significant-digits = 3 - refresh-interval = 5 minutes - } - } - } - advanced.socket { - tcp-no-delay = true - //keep-alive = false - //reuse-address = true - //linger-interval = 0 - //receive-buffer-size = 65535 - //send-buffer-size = 65535 - } - advanced.heartbeat { - interval = 30 seconds - timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} - } - advanced.metadata { - topology-event-debouncer { - window = 1 second - max-events = 20 - } - schema { - enabled = true - # refreshed-keyspaces = [ "ks1", "ks2" ] - request-timeout = ${datastax-java-driver.basic.request.timeout} - request-page-size = ${datastax-java-driver.basic.request.page-size} - debouncer { - window = 1 second - max-events = 20 - } - } - token-map.enabled = true - } - advanced.control-connection { - timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} - schema-agreement { - interval = 200 milliseconds - timeout = 10 seconds - warn-on-failure = true - } - } - advanced.prepared-statements { - prepare-on-all-nodes = true - reprepare-on-up { - enabled = true - check-system-table = false - max-statements = 0 - max-parallelism = 100 - timeout = ${datastax-java-driver.advanced.connection.init-query-timeout} - } - } - advanced.netty { - daemon = false - io-group { - size = 0 - shutdown {quiet-period = 2, timeout = 15, unit = SECONDS} - } - admin-group { - size = 2 - shutdown {quiet-period = 2, timeout = 15, unit = SECONDS} - } - timer { - tick-duration = 100 milliseconds - ticks-per-wheel = 2048 - } - } - advanced.coalescer { - max-runs-with-no-work = 5 - reschedule-interval = 10 microseconds - } - } - actorsystems { - otoroshi { - akka { # otoroshi actorsystem configuration - version = ${akka.version} - log-dead-letters-during-shutdown = false - jvm-exit-on-fatal-error = false - default-dispatcher { - type = Dispatcher - executor = "fork-join-executor" - fork-join-executor { - parallelism-factor = 4.0 - parallelism-factor = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_FACTOR} - parallelism-min = 8 - parallelism-min = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_MIN} - parallelism-max = 128 - parallelism-max = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_MAX} - task-peeking-mode = "FIFO" - task-peeking-mode = ${?OTOROSHI_CORE_DISPATCHER_TASK_PEEKING_MODE} - } - throughput = 1 - throughput = ${?OTOROSHI_CORE_DISPATCHER_THROUGHPUT} - } - http { - parsing { - max-uri-length = 4k - max-method-length = 16 - max-response-reason-length = 64 - max-header-name-length = 128 - max-header-value-length = 16k - max-header-count = 128 - max-chunk-ext-length = 256 - max-chunk-size = 256m - max-chunk-size = ${?AKKA_HTTP_CLIENT_MAX_CHUNK_SIZE} - max-chunk-size = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_CHUNK_SIZE} - max-content-length = infinite - max-content-length = ${?AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT} - max-content-length = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT} - max-to-strict-bytes = infinite - max-to-strict-bytes = ${?AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES} - max-to-strict-bytes = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES} - } - } - } - } - datastore { - akka { - version = ${akka.version} - log-dead-letters-during-shutdown = false - jvm-exit-on-fatal-error = false - default-dispatcher { - type = Dispatcher - executor = "fork-join-executor" - fork-join-executor { - parallelism-factor = 4.0 - parallelism-min = 4 - parallelism-max = 64 - task-peeking-mode = "FIFO" - } - throughput = 1 - } - } - } - } -} - -otoroshi { - domain = ${?app.domain} - maintenanceMode = false # enable global maintenance mode - maintenanceMode = ${?OTOROSHI_MAINTENANCE_MODE_ENABLED} # enable global maintenance mode - secret = "verysecretvaluethatyoumustoverwrite" # the secret used to sign sessions - secret = ${?OTOROSHI_SECRET} # the secret used to sign sessions - admin-api-secret = ${?OTOROSHI_ADMIN_API_SECRET} # the secret for admin api - next { - state-sync-interval = 10000 - state-sync-interval = ${?OTOROSHI_NEXT_STATE_SYNC_INTERVAL} - export-reporting = false - export-reporting = ${?OTOROSHI_NEXT_EXPORT_REPORTING} - monitor-proxy-state-size = false - monitor-proxy-state-size = ${?OTOROSHI_NEXT_MONITOR_PROXY_STATE_SIZE} - monitor-datastore-size = false - monitor-datastore-size = ${?OTOROSHI_NEXT_MONITOR_DATASTORE_SIZE} - plugins { - merge-sync-steps = true - merge-sync-steps = ${?OTOROSHI_NEXT_PLUGINS_MERGE_SYNC_STEPS} - apply-legacy-checks = true - apply-legacy-checks = ${?OTOROSHI_NEXT_PLUGINS_APPLY_LEGACY_CHECKS} - } - } - options { - bypassUserRightsCheck = false - bypassUserRightsCheck = ${?OTOROSHI_OPTIONS_BYPASSUSERRIGHTSCHECK} - emptyContentLengthIsChunked = true - emptyContentLengthIsChunked = ${?OTOROSHI_OPTIONS_EMPTYCONTENTLENGTHISCHUNKED} - detectApiKeySooner = true - detectApiKeySooner = ${?OTOROSHI_OPTIONS_DETECTAPIKEYSOONER} - sendClientChainAsPem = false - sendClientChainAsPem = ${?OTOROSHI_OPTIONS_SENDCLIENTCHAINASPEM} - useOldHeadersComposition = false - useOldHeadersComposition = ${?OTOROSHI_OPTIONS_USEOLDHEADERSCOMPOSITION} - manualDnsResolve = true - manualDnsResolve = ${?OTOROSHI_OPTIONS_MANUALDNSRESOLVE} - useEventStreamForScriptEvents = true - useEventStreamForScriptEvents = ${?OTOROSHI_OPTIONS_USEEVENTSTREAMFORSCRIPTEVENTS} - trustXForwarded = true - trustXForwarded = ${?OTOROSHI_OPTIONS_TRUST_XFORWARDED} - disableFunnyLogos = false - disableFunnyLogos = ${?OTOROSHI_OPTIONS_DISABLE_FUNNY_LOGOS} - staticExposedDomain = ${?OTOROSHI_OPTIONS_STATIC_EXPOSED_DOMAIN} - } - backoffice { - flags { - useAkkaHttpClient = false - useAkkaHttpClient = ${?OTOROSHI_BACKOFFICE_FLAGS_USE_AKKA_HTTP_CLIENT} - logUrl = false - logUrl = ${?OTOROSHI_BACKOFFICE_FLAGS_LOG_URL} - requestTimeout = 60000 - requestTimeout = ${?OTOROSHI_BACKOFFICE_FLAGS_REQUEST_TIMEOUT} - } - } - sessions { - secret = ${otoroshi.secret} - secret = ${?OTOROSHI_SESSIONS_SECRET} - } - cache { - enabled = false - enabled = ${?USE_CACHE} - enabled = ${?OTOROSHI_USE_CACHE} - enabled = ${?OTOROSHI_ENTITIES_CACHE_ENABLED} - ttl = 2000 - ttl = ${?OTOROSHI_ENTITIES_CACHE_TTL} - } - metrics { - enabled = true - enabled = ${?OTOROSHI_METRICS_ENABLED} - every = 30000 - every = ${?OTOROSHI_METRICS_EVERY} - accessKey = ${?app.health.accessKey} - accessKey = ${?OTOROSHI_app.health.accessKey} - accessKey = ${?OTOROSHI_METRICS_ACCESS_KEY} - } - plugins { - packages = [] - packagesStr = ${?OTOROSHI_PLUGINS_SCAN_PACKAGES} - print = false - print = ${?OTOROSHI_PLUGINS_PRINT} - } - scripts { - enabled = true # enable scripts - enabled = ${?OTOROSHI_SCRIPTS_ENABLED} # enable scripts - static { # settings for statically enabled script/plugins - enabled = false - enabled = ${?OTOROSHI_SCRIPTS_STATIC_ENABLED} - transformersRefs = [] - transformersRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_TRANSFORMER_REFS} - transformersConfig = {} - transformersConfigStr= ${?OTOROSHI_SCRIPTS_STATIC_TRANSFORMER_CONFIG} - validatorRefs = [] - validatorRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_VALIDATOR_REFS} - validatorConfig = {} - validatorConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_VALIDATOR_CONFIG} - preRouteRefs = [] - preRouteRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_PRE_ROUTE_REFS} - preRouteConfig = {} - preRouteConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_PRE_ROUTE_CONFIG} - sinkRefs = [] - sinkRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_SINK_REFS} - sinkConfig = {} - sinkConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_SINK_CONFIG} - jobsRefs = [] - jobsRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_JOBS_REFS} - jobsConfig = {} - jobsConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_JOBS_CONFIG} - } - } - tls = ${otoroshi.ssl} - ssl { - # the cipher suites used by otoroshi TLS termination - cipherSuitesJDK11 = ["TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"] - cipherSuitesJDK8 = ["TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"] - # cipherSuites = ["TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"] - cipherSuites = [] - # the protocols used by otoroshi TLS termination - protocolsJDK11 = ["TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"] - protocolsJDK8 = ["SSLv2Hello", "TLSv1", "TLSv1.1", "TLSv1.2"] - # protocols = ["TLSv1.3", "TLSv1.2"] - protocols = [] - # the JDK cacert access - cacert { - path = "$JAVA_HOME/lib/security/cacerts" - password = "changeit" - } - # the mtls mode - fromOutside { - clientAuth = "None" - clientAuth = ${?SSL_OUTSIDE_CLIENT_AUTH} - clientAuth = ${?OTOROSHI_SSL_OUTSIDE_CLIENT_AUTH} - } - # the default trust mode - trust { - all = false - all = ${?OTOROSHI_SSL_TRUST_ALL} - } - # some initial cacert access, useful to include non standard CA when starting - initialCacert = ${?CLUSTER_WORKER_INITIAL_CACERT} - initialCacert = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CACERT} - initialCacert = ${?INITIAL_CACERT} - initialCacert = ${?OTOROSHI_INITIAL_CACERT} - initialCert = ${?CLUSTER_WORKER_INITIAL_CERT} - initialCert = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CERT} - initialCert = ${?INITIAL_CERT} - initialCert = ${?OTOROSHI_INITIAL_CERT} - initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY} - initialCertKey = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CERT_KEY} - initialCertKey = ${?INITIAL_CERT_KEY} - initialCertKey = ${?OTOROSHI_INITIAL_CERT_KEY} - # initialCerts = [] - } - cluster { - mode = "off" # can be "off", "leader", "worker" - mode = ${?CLUSTER_MODE} # can be "off", "leader", "worker" - mode = ${?OTOROSHI_CLUSTER_MODE} # can be "off", "leader", "worker" - compression = -1 # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9 - compression = ${?CLUSTER_COMPRESSION} # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9 - compression = ${?OTOROSHI_CLUSTER_COMPRESSION} # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9 - retryDelay = 300 # the delay before retrying a request to leader - retryDelay = ${?CLUSTER_RETRY_DELAY} # the delay before retrying a request to leader - retryDelay = ${?OTOROSHI_CLUSTER_RETRY_DELAY} # the delay before retrying a request to leader - retryFactor = 2 # the retry factor to avoid high load on failing nodes - retryFactor = ${?CLUSTER_RETRY_FACTOR} # the retry factor to avoid high load on failing nodes - retryFactor = ${?OTOROSHI_CLUSTER_RETRY_FACTOR} # the retry factor to avoid high load on failing nodes - selfAddress = ${?CLUSTER_SELF_ADDRESS} # the cluster slefAddress - selfAddress = ${?OTOROSHI_CLUSTER_SELF_ADDRESS} # the cluster selfAddress - autoUpdateState = true # auto update cluster state with a job (more efficient) - autoUpdateState = ${?CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (more efficient - autoUpdateState = ${?OTOROSHI_CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (more efficient - mtls { - # certs = [] - # trustedCerts = [] - enabled = false # enable mtls - enabled = ${?CLUSTER_MTLS_ENABLED} # enable mtls - enabled = ${?OTOROSHI_CLUSTER_MTLS_ENABLED} # enable mtls - loose = false # loose verification - loose = ${?CLUSTER_MTLS_LOOSE} # loose verification - loose = ${?OTOROSHI_CLUSTER_MTLS_LOOSE} # loose verification - trustAll = false # trust any CA - trustAll = ${?CLUSTER_MTLS_TRUST_ALL} # trust any CA - trustAll = ${?OTOROSHI_CLUSTER_MTLS_TRUST_ALL} # trust any CA - } - leader { - name = ${?CLUSTER_LEADER_NAME} # the leader name - name = ${?OTOROSHI_CLUSTER_LEADER_NAME} # the leader name - urls = ["http://127.0.0.1:8080"] # the leader urls - url = ${?CLUSTER_LEADER_URL} # the leader url - url = ${?OTOROSHI_CLUSTER_LEADER_URL} # the leader url - host = "otoroshi-api.oto.tools" # the leaders api hostname - host = ${?CLUSTER_LEADER_HOST} # the leaders api hostname - host = ${?OTOROSHI_CLUSTER_LEADER_HOST} # the leaders api hostname - clientId = "admin-api-apikey-id" # the leaders apikey id to access otoroshi admin api - clientId = ${?CLUSTER_LEADER_CLIENT_ID} # the leaders apikey id to access otoroshi admin api - clientId = ${?OTOROSHI_CLUSTER_LEADER_CLIENT_ID} # the leaders apikey id to access otoroshi admin api - clientSecret = "admin-api-apikey-secret" # the leaders apikey secret to access otoroshi admin api - clientSecret = ${?CLUSTER_LEADER_CLIENT_SECRET} # the leaders apikey secret to access otoroshi admin api - clientSecret = ${?OTOROSHI_CLUSTER_LEADER_CLIENT_SECRET} # the leaders apikey secret to access otoroshi admin api - groupingBy = 50 # items grouping when streaming state - groupingBy = ${?CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state - groupingBy = ${?OTOROSHI_CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state - cacheStateFor = 10000 # the ttl for local state cache - cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache - cacheStateFor = ${?OTOROSHI_CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache - stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose - stateDumpPath = ${?OTOROSHI_CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose - } - worker { - name = ${?CLUSTER_WORKER_NAME} # the workers name - name = ${?OTOROSHI_CLUSTER_WORKER_NAME} # the workers name - retries = 3 # the number of retries when pushing quotas/pulling state - retries = ${?CLUSTER_WORKER_RETRIES} # the number of retries when pushing quotas/pulling state - retries = ${?OTOROSHI_CLUSTER_WORKER_RETRIES} # the number of retries when pushing quotas/pulling state - timeout = 10000 # the workers timeout when interacting with leaders - timeout = ${?CLUSTER_WORKER_TIMEOUT} # the workers timeout when interacting with leaders - timeout = ${?OTOROSHI_CLUSTER_WORKER_TIMEOUT} # the workers timeout when interacting with leaders - tenants = [] # the list of organization served by this worker. If none, it's all - tenantsStr = ${?CLUSTER_WORKER_TENANTS} # the list (coma separated) of organization served by this worker. If none, it's all - tenantsStr = ${?OTOROSHI_CLUSTER_WORKER_TENANTS} # the list (coma separated) of organization served by this worker. If none, it's all - dbpath = ${?CLUSTER_WORKER_DB_PATH} # state dump path for debugging purpose - dbpath = ${?OTOROSHI_CLUSTER_WORKER_DB_PATH} # state dump path for debugging purpose - dataStaleAfter = 600000 # the amount of time needed to consider state is stale - dataStaleAfter = ${?CLUSTER_WORKER_DATA_STALE_AFTER} # the amount of time needed to consider state is stale - dataStaleAfter = ${?OTOROSHI_CLUSTER_WORKER_DATA_STALE_AFTER} # the amount of time needed to consider state is stale - swapStrategy = "Merge" # the internal memory store strategy, can be Replace or Merge - swapStrategy = ${?CLUSTER_WORKER_SWAP_STRATEGY} # the internal memory store strategy, can be Replace or Merge - swapStrategy = ${?OTOROSHI_CLUSTER_WORKER_SWAP_STRATEGY} # the internal memory store strategy, can be Replace or Merge - modern = false # use a modern store implementation - modern = ${?CLUSTER_WORKER_STORE_MODERN} - modern = ${?OTOROSHI_CLUSTER_WORKER_STORE_MODERN} - state { - retries = ${otoroshi.cluster.worker.retries} # the number of retries when pulling state - retries = ${?CLUSTER_WORKER_STATE_RETRIES} # the number of retries when pulling state - retries = ${?OTOROSHI_CLUSTER_WORKER_STATE_RETRIES} # the number of retries when pulling state - pollEvery = 10000 # polling interval - pollEvery = ${?CLUSTER_WORKER_POLL_EVERY} # polling interval - pollEvery = ${?OTOROSHI_CLUSTER_WORKER_POLL_EVERY} # polling interval - timeout = ${otoroshi.cluster.worker.timeout} # the workers timeout when polling state - timeout = ${?CLUSTER_WORKER_POLL_TIMEOUT} # the workers timeout when polling state - timeout = ${?OTOROSHI_CLUSTER_WORKER_POLL_TIMEOUT} # the workers timeout when polling state - } - quotas { - retries = ${otoroshi.cluster.worker.retries} # the number of retries when pushing quotas - retries = ${?CLUSTER_WORKER_QUOTAS_RETRIES} # the number of retries when pushing quotas - retries = ${?OTOROSHI_CLUSTER_WORKER_QUOTAS_RETRIES} # the number of retries when pushing quotas - pushEvery = 10000 # pushing interval - pushEvery = ${?CLUSTER_WORKER_PUSH_EVERY} # pushing interval - pushEvery = ${?OTOROSHI_CLUSTER_WORKER_PUSH_EVERY} # pushing interval - timeout = ${otoroshi.cluster.worker.timeout} # the workers timeout when pushing quotas - timeout = ${?CLUSTER_WORKER_PUSH_TIMEOUT} # the workers timeout when pushing quotas - timeout = ${?OTOROSHI_CLUSTER_WORKER_PUSH_TIMEOUT} # the workers timeout when pushing quotas - } - } - analytics { # settings for the analytics actor system which is separated from otoroshi default one for performance reasons - pressure { - enabled = true - enabled = ${?OTOROSHI_ANALYTICS_PRESSURE_ENABLED} - } - actorsystem { - akka { - version = ${akka.version} - log-dead-letters-during-shutdown = false - jvm-exit-on-fatal-error = false - default-dispatcher { - type = Dispatcher - executor = "fork-join-executor" - fork-join-executor { - parallelism-factor = 4.0 - parallelism-min = 4 - parallelism-max = 64 - task-peeking-mode = "FIFO" - } - throughput = 1 - } - # http { - # parsing { - # max-uri-length = 4k - # max-method-length = 16 - # max-response-reason-length = 64 - # max-header-name-length = 128 - # max-header-value-length = 16k - # max-header-count = 128 - # max-chunk-ext-length = 256 - # max-chunk-size = 256m - # max-chunk-size = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CHUNK_SIZE} - # max-chunk-size = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_CHUNK_SIZE} - # max-content-length = infinite - # max-content-length = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT} - # max-content-length = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT} - # max-to-strict-bytes = infinite - # max-to-strict-bytes = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_TO_STRICT_BYTES} - # max-to-strict-bytes = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_TO_STRICT_BYTES} - # } - # } - } - } - } - } - headers { # the default headers value for specific otoroshi headers - trace.label = "Otoroshi-Viz-From-Label" - trace.from = "Otoroshi-Viz-From" - trace.parent = "Otoroshi-Parent-Request" - request.adminprofile = "Otoroshi-Admin-Profile" - request.simpleapiclientid = "x-api-key" - request.clientid = "Otoroshi-Client-Id" - request.clientsecret = "Otoroshi-Client-Secret" - request.id = "Otoroshi-Request-Id" - request.timestamp = "Otoroshi-Request-Timestamp" - request.bearer = "Otoroshi-Token" - request.authorization = "Otoroshi-Authorization" - response.proxyhost = "Otoroshi-Proxied-Host" - response.error = "Otoroshi-Error" - response.errormsg = "Otoroshi-Error-Msg" - response.proxylatency = "Otoroshi-Proxy-Latency" - response.upstreamlatency = "Otoroshi-Upstream-Latency" - response.dailyquota = "Otoroshi-Daily-Calls-Remaining" - response.monthlyquota = "Otoroshi-Monthly-Calls-Remaining" - comm.state = "Otoroshi-State" - comm.stateresp = "Otoroshi-State-Resp" - comm.claim = "Otoroshi-Claim" - healthcheck.test = "Otoroshi-Health-Check-Logic-Test" - healthcheck.testresult = "Otoroshi-Health-Check-Logic-Test-Result" - jwt.issuer = "Otoroshi" - canary.tracker = "Otoroshi-Canary-Id" - client.cert.chain = "Otoroshi-Client-Cert-Chain" - - request.jwtAuthorization = "access_token" - request.bearerAuthorization = "bearer_auth" - request.basicAuthorization = "basic_auth" - } - requests { - validate = true - validate = ${?OTOROSHI_REQUESTS_VALIDATE} - maxUrlLength = ${akka.http.parsing.max-uri-length} - maxCookieLength = ${akka.http.parsing.max-header-value-length} - maxHeaderNameLength = ${akka.http.parsing.max-header-name-length} - maxHeaderValueLength = ${akka.http.parsing.max-header-value-length} - } - jmx { - enabled = false - enabled = ${?OTOROSHI_JMX_ENABLED} - port = 16000 - port = ${?OTOROSHI_JMX_PORT} - } - loggers { - } - provider { - dashboardUrl = ${?OTOROSHI_PROVIDER_DASHBOARD_URL} - jsUrl = ${?OTOROSHI_PROVIDER_JS_URL} - cssUrl = ${?OTOROSHI_PROVIDER_CSS_URL} - secret = "secret" - secret = ${?OTOROSHI_PROVIDER_SECRET} - title = "Provider's dashboard" - title = ${?OTOROSHI_PROVIDER_TITLE} - } - healthcheck { - workers = 4 - workers = ${?OTOROSHI_HEALTHCHECK_WORKERS} - block-on-red = false - block-on-red = ${?OTOROSHI_HEALTHCHECK_BLOCK_ON_RED} - block-on-red = ${?OTOROSHI_HEALTHCHECK_BLOCK_ON_500} - ttl = 60000 - ttl = ${?OTOROSHI_HEALTHCHECK_TTL} - ttl-only = true - ttl-only = ${?OTOROSHI_HEALTHCHECK_TTL_ONLY} - } - vaults { - enabled = false - enabled = ${?OTOROSHI_VAULTS_ENABLED} - secrets-ttl = 300000 # 5 minutes - secrets-ttl = ${?OTOROSHI_VAULTS_SECRETS_TTL} - cached-secrets = 10000 - cached-secrets = ${?OTOROSHI_VAULTS_CACHED_SECRETS} - read-ttl = 10000 # 10 seconds - read-ttl = ${?OTOROSHI_VAULTS_READ_TTL} - parallel-fetchs = 4 - parallel-fetchs = ${?OTOROSHI_VAULTS_PARALLEL_FETCHS} - # if enabled, only leader nodes fetches the secrets. - # entities with secret values filled are then sent to workers when they poll the cluster state. - # only works if `otoroshi.cluster.autoUpdateState=true` - leader-fetch-only = false - leader-fetch-only = ${?OTOROSHI_VAULTS_LEADER_FETCH_ONLY} - env { - type = "env" - prefix = ${?OTOROSHI_VAULTS_ENV_PREFIX} - } - # hashicorpvault { - # type = "hashicorp-vault" - # url = "http://127.0.0.1:8200" - # mount = "kv" - # kv = "v2" - # token = "root" - # } - } -} - - -http.port = 8080 # the main http port for the otoroshi server -http.port = ${?otoroshi.http.port} # the main http port for the otoroshi server -http.port = ${?PORT} # the main http port for the otoroshi server -http.port = ${?OTOROSHI_PORT} # the main http port for the otoroshi server -http.port = ${?OTOROSHI_HTTP_PORT} # the main http port for the otoroshi server -play.server.http.port = ${http.port} # the main http port for the otoroshi server -play.server.http.port = ${?PORT} # the main http port for the otoroshi server -play.server.http.port = ${?OTOROSHI_PORT} # the main http port for the otoroshi server -play.server.http.port = ${?OTOROSHI_HTTP_PORT} # the main http port for the otoroshi server -https.port = 8443 # the main https port for the otoroshi server -https.port = ${?otoroshi.https.port} # the main https port for the otoroshi server -https.port = ${?HTTPS_PORT} # the main https port for the otoroshi server -https.port = ${?OTOROSHI_HTTPS_PORT} # the main https port for the otoroshi server - -play.server.https.engineProvider = "otoroshi.ssl.DynamicSSLEngineProvider" # the module to handle TLS connections dynamically -play.server.https.keyStoreDumpPath = ${?HTTPS_KEYSTORE_DUMP_PATH} # the file path where the TLSContext will be dumped (for debugging purposes only) -play.server.https.keyStoreDumpPath = ${?OTOROSHI_HTTPS_KEYSTORE_DUMP_PATH} # the file path where the TLSContext will be dumped (for debugging purposes only) - -play.http.secret.key = ${otoroshi.secret} # the secret used to signed session cookies -play.http.secret.key = ${?PLAY_CRYPTO_SECRET} # the secret used to signed session cookies -play.http.secret.key = ${?OTOROSHI_CRYPTO_SECRET} # the secret used to signed session cookies - -play.server.http.idleTimeout = 3600s # the default server idle timeout -play.server.http.idleTimeout = ${?PLAY_SERVER_IDLE_TIMEOUT} # the default server idle timeout -play.server.http.idleTimeout = ${?OTOROSHI_SERVER_IDLE_TIMEOUT} # the default server idle timeout -play.server.akka.requestTimeout = 3600s # the default server idle timeout (for akka server specifically) -play.server.akka.requestTimeout = ${?PLAY_SERVER_REQUEST_TIMEOUT} # the default server idle timeout (for akka server specifically) -play.server.akka.requestTimeout = ${?OTOROSHI_SERVER_REQUEST_TIMEOUT} # the default server idle timeout (for akka server specifically) - -http2.enabled = true # enable HTTP2 support -http2.enabled = ${?otoroshi.http2.enabled} -http2.enabled = ${?HTTP2_ENABLED} # enable HTTP2 support -http2.enabled = ${?OTOROSHI_HTTP2_ENABLED} # enable HTTP2 support - -play.server.https.keyStore.path=${?HTTPS_KEYSTORE_PATH} # settings for the default server keystore -play.server.https.keyStore.path=${?OTOROSHI_HTTPS_KEYSTORE_PATH} # settings for the default server keystore -play.server.https.keyStore.type=${?HTTPS_KEYSTORE_TYPE} # settings for the default server keystore -play.server.https.keyStore.type=${?OTOROSHI_HTTPS_KEYSTORE_TYPE} # settings for the default server keystore -play.server.https.keyStore.password=${?HTTPS_KEYSTORE_PASSWORD} # settings for the default server keystore -play.server.https.keyStore.password=${?OTOROSHI_HTTPS_KEYSTORE_PASSWORD} # settings for the default server keystore -play.server.https.keyStore.algorithm=${?HTTPS_KEYSTORE_ALGO} # settings for the default server keystore -play.server.https.keyStore.algorithm=${?OTOROSHI_HTTPS_KEYSTORE_ALGO} # settings for the default server keystore - - - - -play.application.loader = "otoroshi.loader.OtoroshiLoader" # the loader used to launch otoroshi - -play.http { - session { - secure = false # the cookie for otoroshi backoffice should be exhanged over https only - secure = ${?SESSION_SECURE_ONLY} # the cookie for otoroshi backoffice should be exhanged over https only - secure = ${?OTOROSHI_SESSION_SECURE_ONLY} # the cookie for otoroshi backoffice should be exhanged over https only - httpOnly = true # the cookie for otoroshi backoffice is not accessible from javascript - maxAge = 259200000 # the cookie for otoroshi backoffice max age - maxAge = ${?SESSION_MAX_AGE} # the cookie for otoroshi backoffice max age - maxAge = ${?OTOROSHI_SESSION_MAX_AGE} # the cookie for otoroshi backoffice max age - # domain = "."${?app.domain} # the cookie for otoroshi backoffice domain - domain = "."${otoroshi.domain} # the cookie for otoroshi backoffice domain - domain = ${?SESSION_DOMAIN} # the cookie for otoroshi backoffice domain - domain = ${?OTOROSHI_SESSION_DOMAIN} # the cookie for otoroshi backoffice domain - cookieName = "otoroshi-session" # the cookie for otoroshi backoffice name - cookieName = ${?SESSION_NAME} # the cookie for otoroshi backoffice name - cookieName = ${?OTOROSHI_SESSION_NAME} # the cookie for otoroshi backoffice name - } -} - - - - - - -akka { # akka specific configuration - version = "2.6.19" - loglevel = ERROR - logger-startup-timeout = 60s - log-dead-letters-during-shutdown = false - jvm-exit-on-fatal-error = false - actor { - default-dispatcher { - type = Dispatcher - executor = "fork-join-executor" - fork-join-executor { - parallelism-factor = 4.0 - parallelism-factor = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_FACTOR} - parallelism-min = 8 - parallelism-min = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_MIN} - parallelism-max = 64 - parallelism-max = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_MAX} - task-peeking-mode = "FIFO" - task-peeking-mode = ${?OTOROSHI_AKKA_DISPATCHER_TASK_PEEKING_MODE} - } - throughput = 1 - throughput = ${?OTOROSHI_AKKA_DISPATCHER_THROUGHPUT} - } - } - http { - server { - server-header = otoroshi - max-connections = 2048 - remote-address-header = on - raw-request-uri-header = on - pipelining-limit = 64 - backlog = 512 - socket-options { - so-receive-buffer-size = undefined - so-send-buffer-size = undefined - so-reuse-address = undefined - so-traffic-class = undefined - tcp-keep-alive = true - tcp-oob-inline = undefined - tcp-no-delay = undefined - } - http2 { - request-entity-chunk-size = 65536 b - incoming-connection-level-buffer-size = 10 MB - incoming-stream-level-buffer-size = 512kB - } - } - client { - user-agent-header = Otoroshi-akka - socket-options { - so-receive-buffer-size = undefined - so-send-buffer-size = undefined - so-reuse-address = undefined - so-traffic-class = undefined - tcp-keep-alive = true - tcp-oob-inline = undefined - tcp-no-delay = undefined - } - } - host-connection-pool { - max-connections = 512 - max-open-requests = 2048 - pipelining-limit = 32 - client { - user-agent-header = otoroshi - socket-options { - so-receive-buffer-size = undefined - so-send-buffer-size = undefined - so-reuse-address = undefined - so-traffic-class = undefined - tcp-keep-alive = true - tcp-oob-inline = undefined - tcp-no-delay = undefined - } - } - } - parsing { - max-uri-length = 4k - max-method-length = 16 - max-response-reason-length = 128 - max-header-name-length = 128 - max-header-value-length = 16k - max-header-count = 128 - max-chunk-ext-length = 256 - max-chunk-size = 256m - max-chunk-size = ${?AKKA_HTTP_SERVER_MAX_CHUNK_SIZE} - max-chunk-size = ${?OTOROSHI_AKKA_HTTP_SERVER_MAX_CHUNK_SIZE} - max-content-length = infinite - max-content-length = ${?AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT} - max-content-length = ${?OTOROSHI_AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT} - } - } -}
-

More config. options

-

See default configuration at

- -

Configuration with env. variables

-

Eevery property in the configuration file can be overriden by an environment variable if it has env variable override written like ${?ENV_VARIABLE}).

-

Reference configuration for env. variables

-
app {
-  storage = ${?APP_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg  
-  storage = ${?OTOROSHI_STORAGE} # the storage used by otoroshi. possible values are redis, inmemory, file, http, s3, cassandra, lettuce, experimental-pg  
-  storageRoot = ${?APP_STORAGE_ROOT} # the prefix used for storage keys
-  storageRoot = ${?OTOROSHI_STORAGE_ROOT} # the prefix used for storage keys
-  eventsName = ${?APP_EVENTS_NAME} # the name of the event producer
-  eventsName = ${?OTOROSHI_EVENTS_NAME} # the name of the event producer
-  importFrom = ${?APP_IMPORT_FROM} # file path to import otoroshi initial configuration
-  importFrom = ${?OTOROSHI_IMPORT_FROM} # file path to import otoroshi initial configuration
-  env = ${?APP_ENV} # env name, should always be prod except in dev mode
-  env = ${?OTOROSHI_ENV} # env name, should always be prod except in dev mode
-  domain = ${?APP_DOMAIN} # default domain for basic otoroshi services
-  domain = ${?OTOROSHI_DOMAIN} # default domain for basic otoroshi services
-  commitId = ${?COMMIT_ID}
-  commitId = ${?OTOROSHI_COMMIT_ID}
-  rootScheme = ${?APP_ROOT_SCHEME} # default root scheme when composing urls
-  rootScheme = ${?OTOROSHI_ROOT_SCHEME} # default root scheme when composing urls
-  throttlingWindow = ${?THROTTLING_WINDOW} # the number of second used to compute throttling number
-  throttlingWindow = ${?OTOROSHI_THROTTLING_WINDOW} # the number of second used to compute throttling number
-  checkForUpdates = ${?CHECK_FOR_UPDATES} # enable automatic version update checks
-  checkForUpdates = ${?OTOROSHI_CHECK_FOR_UPDATES} # enable automatic version update checks
-  overheadThreshold = ${?OVERHEAD_THRESHOLD} # the value threshold (in milliseconds) used to send HighOverheadAlert
-  overheadThreshold = ${?OTOROSHI_OVERHEAD_THRESHOLD} # the value threshold (in milliseconds) used to send HighOverheadAlert
-  adminLogin = ${?OTOROSHI_INITIAL_ADMIN_LOGIN} # the initial admin login
-  adminPassword = ${?OTOROSHI_INITIAL_ADMIN_PASSWORD} # the initial admin password
-  initialCustomization = ${?OTOROSHI_INITIAL_CUSTOMIZATION} # otoroshi inital configuration that will be merged with a new confguration. Shaped like an otoroshi export
-  boot {
-    globalWait = ${?OTOROSHI_BOOT_GLOBAL_WAIT} # should we wait until everything is setup to accept http requests
-    globalWaitTimeout = ${?OTOROSHI_BOOT_GLOBAL_WAIT_TIMEOUT} # max wait before accepting requests
-    waitForPluginsSearch = ${?OTOROSHI_BOOT_WAIT_FOR_PLUGINS_SEARCH} # should we wait for classpath plugins search before accepting http requests
-    waitForPluginsSearchTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_PLUGINS_SEARCH_TIMEOUT} # max wait for classpath plugins search before accepting http requests
-    waitForScriptsCompilation = ${?OTOROSHI_BOOT_WAIT_FOR_SCRIPTS_COMPILATION} # should we wait for plugins compilation before accepting http requests
-    waitForScriptsCompilationTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_SCRIPTS_COMPILATION_TIMEOUT} # max wait for plugins compilation before accepting http requests 
-    waitForTlsInit = ${?OTOROSHI_BOOT_WAIT_FOR_TLS_INIT} # should we wait for first TLS context initialization before accepting http requests
-    waitForTlsInitTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_TLS_INIT_TIMEOUT} # max wait for first TLS context initialization before accepting http requests
-    waitForFirstClusterFetch = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_FETCH} # should we wait for first cluster initialization before accepting http requests
-    waitForFirstClusterFetchTimeout = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_TIMEOUT} # max wait for first cluster initialization before accepting http requests
-    waitForFirstClusterStateCache = ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_STATE_CACHE} # should we wait for first cluster initialization before accepting http requests
-    waitForFirstClusterStateCacheTimeout =  ${?OTOROSHI_BOOT_WAIT_FOR_FIRST_CLUSTER_STATE_CACHE_TIMEOUT} # max wait for first cluster initialization before accepting http requests
-  }
-  instance {
-    instanceId = ${?OTOROSHI_INSTANCE_ID} # the instance id
-    number =  ${?OTOROSHI_INSTANCE_NUMBER} # the instance number. Can be found in otoroshi events
-    number =  ${?INSTANCE_NUMBER} # the instance number. Can be found in otoroshi events
-    name = ${?OTOROSHI_INSTANCE_NAME} # instance name
-    zone = ${?OTOROSHI_INSTANCE_ZONE} # instance zone (optional)
-    region = ${?OTOROSHI_INSTANCE_REGION} # instance region (optional)
-    dc = ${?OTOROSHI_INSTANCE_DATACENTER} # instance dc (optional)
-    provider = ${?OTOROSHI_INSTANCE_PROVIDER} # instance provider (optional)
-    rack = ${?OTOROSHI_INSTANCE_RACK} # instance rack (optional)
-    title = ${?OTOROSHI_INSTANCE_TITLE} # the title displayed in UI top left
-  }
-  }
-  health {
-    limit = ${?HEALTH_LIMIT} # the value threshold (in milliseconds) used to indicate if an otoroshi instance is healthy or not
-    limit = ${?OTOROSHI_HEALTH_LIMIT} # the value threshold (in milliseconds) used to indicate if an otoroshi instance is healthy or not
-    accessKey = ${?HEALTH_ACCESS_KEY} # the key to access /health edpoint
-    accessKey = ${?OTOROSHI_HEALTH_ACCESS_KEY} # the key to access /health edpoint
-  }
-  snowflake {
-    seed = ${?INSTANCE_NUMBER} # the seed number used to generate unique ids. Should be different for every instances
-    seed = ${?OTOROSHI_INSTANCE_NUMBER} # the seed number used to generate unique ids. Should be different for every instances
-    seed = ${?SNOWFLAKE_SEED} # the seed number used to generate unique ids. Should be different for every instances
-    seed = ${?OTOROSHI_SNOWFLAKE_SEED} # the seed number used to generate unique ids. Should be different for every instances
-  }
-  events {
-    maxSize = ${?MAX_EVENTS_SIZE} # the amount of event kept in the datastore
-    maxSize = ${?OTOROSHI_MAX_EVENTS_SIZE} # the amount of event kept in the datastore
-  }
-  exposed-ports {
-    http = ${?APP_EXPOSED_PORTS_HTTP} # the exposed http port for otoroshi (when in a container or behind a proxy)
-    http = ${?OTOROSHI_EXPOSED_PORTS_HTTP} # the exposed http port for otoroshi (when in a container or behind a proxy)
-    https = ${?APP_EXPOSED_PORTS_HTTPS} # the exposed https port for otoroshi (when in a container or behind a proxy
-    https = ${?OTOROSHI_EXPOSED_PORTS_HTTPS} # the exposed https port for otoroshi (when in a container or behind a proxy
-  }
-  backoffice {
-    exposed = ${?APP_BACKOFFICE_EXPOSED} # expose the backoffice ui
-    exposed = ${?OTOROSHI_BACKOFFICE_EXPOSED} # expose the backoffice ui
-    subdomain = ${?APP_BACKOFFICE_SUBDOMAIN} # the backoffice subdomain
-    subdomain = ${?OTOROSHI_BACKOFFICE_SUBDOMAIN} # the backoffice subdomain
-    domainsStr = ${?APP_BACKOFFICE_DOMAINS} # the backoffice domains
-    domainsStr = ${?OTOROSHI_BACKOFFICE_DOMAINS} # the backoffice domains
-    session {
-      exp = ${?APP_BACKOFFICE_SESSION_EXP} # the backoffice cookie expiration
-      exp = ${?OTOROSHI_BACKOFFICE_SESSION_EXP} # the backoffice cookie expiration
-    }
-  }
-  privateapps {
-    subdomain = ${?APP_PRIVATEAPPS_SUBDOMAIN} # privateapps (proxy sso) domain
-    subdomain = ${?OTOROSHI_PRIVATEAPPS_SUBDOMAIN} # privateapps (proxy sso) domain
-    domainsStr = ${?APP_PRIVATEAPPS_DOMAINS}
-    domainsStr = ${?OTOROSHI_PRIVATEAPPS_DOMAINS}
-    session {
-      exp = ${?APP_PRIVATEAPPS_SESSION_EXP} # the privateapps cookie expiration
-      exp = ${?OTOROSHI_PRIVATEAPPS_SESSION_EXP} # the privateapps cookie expiration
-    }
-  }
-  adminapi {
-    exposed = ${?ADMIN_API_EXPOSED} # expose the admin api
-    exposed = ${?OTOROSHI_ADMIN_API_EXPOSED} # expose the admin api
-    targetSubdomain = ${?ADMIN_API_TARGET_SUBDOMAIN} # admin api target subdomain as targeted by otoroshi service
-    targetSubdomain = ${?OTOROSHI_ADMIN_API_TARGET_SUBDOMAIN} # admin api target subdomain as targeted by otoroshi service
-    exposedSubdomain = ${?ADMIN_API_EXPOSED_SUBDOMAIN} # admin api exposed subdomain as exposed by otoroshi service
-    exposedSubdomain = ${?OTOROSHI_ADMIN_API_EXPOSED_SUBDOMAIN} # admin api exposed subdomain as exposed by otoroshi service
-    additionalExposedDomain = ${?ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN} # admin api additional exposed subdomain as exposed by otoroshi service
-    additionalExposedDomain = ${?OTOROSHI_ADMIN_API_ADDITIONAL_EXPOSED_DOMAIN} # admin api additional exposed subdomain as exposed by otoroshi service
-    domainsStr = ${?ADMIN_API_DOMAINS}
-    domainsStr = ${?OTOROSHI_ADMIN_API_DOMAINS}
-    exposedDomainsStr = ${?ADMIN_API_EXPOSED_DOMAINS}
-    exposedDomainsStr = ${?OTOROSHI_ADMIN_API_EXPOSED_DOMAINS}
-    defaultValues {
-      backOfficeGroupId = ${?ADMIN_API_GROUP} # default value for admin api service group
-      backOfficeGroupId = ${?OTOROSHI_ADMIN_API_GROUP} # default value for admin api service group
-      backOfficeApiKeyClientId = ${?ADMIN_API_CLIENT_ID}  # default value for admin api apikey id
-      backOfficeApiKeyClientId = ${?OTOROSHI_ADMIN_API_CLIENT_ID}  # default value for admin api apikey id
-      backOfficeApiKeyClientSecret = ${?otoroshi.admin-api-secret} # default value for admin api apikey secret
-      backOfficeApiKeyClientSecret = ${?OTOROSHI_otoroshi.admin-api-secret} # default value for admin api apikey secret
-      backOfficeApiKeyClientSecret = ${?ADMIN_API_CLIENT_SECRET} # default value for admin api apikey secret
-      backOfficeApiKeyClientSecret = ${?OTOROSHI_ADMIN_API_CLIENT_SECRET} # default value for admin api apikey secret
-      backOfficeServiceId = ${?ADMIN_API_SERVICE_ID} # default value for admin api service id
-      backOfficeServiceId = ${?OTOROSHI_ADMIN_API_SERVICE_ID} # default value for admin api service id
-    }
-    proxy {
-      https = ${?ADMIN_API_HTTPS} # backoffice proxy admin api over https
-      https = ${?OTOROSHI_ADMIN_API_HTTPS} # backoffice proxy admin api over https
-      local = ${?ADMIN_API_LOCAL} # backoffice proxy admin api on localhost
-      local = ${?OTOROSHI_ADMIN_API_LOCAL} # backoffice proxy admin api on localhost
-    }
-  }
-  claim {
-    sharedKey = ${?CLAIM_SHAREDKEY} # the default secret used to sign otoroshi exchange protocol tokens
-    sharedKey = ${?OTOROSHI_CLAIM_SHAREDKEY} # the default secret used to sign otoroshi exchange protocol tokens
-  }
-  webhooks {
-  }
-  redis { # configuration to fetch/store otoroshi state from a redis datastore using rediscala
-    host = ${?REDIS_HOST}
-    host = ${?OTOROSHI_REDIS_HOST}
-    port = ${?REDIS_PORT}
-    port = ${?OTOROSHI_REDIS_PORT}
-    password = ${?REDIS_PASSWORD}
-    password = ${?OTOROSHI_REDIS_PASSWORD}
-    windowSize = ${?REDIS_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_REDIS_WINDOW_SIZE}
-    slavesStr = ${?REDIS_SLAVES}
-    slavesStr = ${?OTOROSHI_REDIS_SLAVES}
-    slavesStr = ${?REDIS_MEMBERS}
-    slavesStr = ${?OTOROSHI_REDIS_MEMBERS}
-    useScan =  ${?REDIS_USE_SCAN}
-    useScan =  ${?OTOROSHI_REDIS_USE_SCAN}
-    pool {
-      members = ${?REDIS_POOL_MEMBERS}
-      members = ${?OTOROSHI_REDIS_POOL_MEMBERS}
-    }
-    mpool {
-      membersStr = ${?REDIS_MPOOL_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_MPOOL_MEMBERS}
-    }
-    lf {
-      master {
-        host = ${?REDIS_LF_HOST}
-        host = ${?OTOROSHI_REDIS_LF_HOST}
-        port = ${?REDIS_LF_PORT}
-        port = ${?OTOROSHI_REDIS_LF_PORT}
-        password = ${?REDIS_LF_PASSWORD}
-        password = ${?OTOROSHI_REDIS_LF_PASSWORD}
-      }
-      slavesStr = ${?REDIS_LF_SLAVES}
-      slavesStr = ${?OTOROSHI_REDIS_LF_SLAVES}
-      slavesStr = ${?REDIS_LF_MEMBERS}
-      slavesStr = ${?OTOROSHI_REDIS_LF_MEMBERS}
-    }
-    sentinels {
-      master = ${?REDIS_SENTINELS_MASTER}
-      master = ${?OTOROSHI_REDIS_SENTINELS_MASTER}
-      password = ${?REDIS_SENTINELS_PASSWORD}
-      password = ${?OTOROSHI_REDIS_SENTINELS_PASSWORD}
-      db = ${?REDIS_SENTINELS_DB}
-      db = ${?OTOROSHI_REDIS_SENTINELS_DB}
-      name = ${?REDIS_SENTINELS_NAME}
-      name = ${?OTOROSHI_REDIS_SENTINELS_NAME}
-      membersStr = ${?REDIS_SENTINELS_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_SENTINELS_MEMBERS}
-      lf {
-        master = ${?REDIS_SENTINELS_LF_MASTER}
-        master = ${?OTOROSHI_REDIS_SENTINELS_LF_MASTER}
-        membersStr = ${?REDIS_SENTINELS_LF_MEMBERS}
-        membersStr = ${?OTOROSHI_REDIS_SENTINELS_LF_MEMBERS}
-      }
-    }
-    cluster {
-      membersStr = ${?REDIS_CLUSTER_MEMBERS}
-      membersStr = ${?OTOROSHI_REDIS_CLUSTER_MEMBERS}
-    }
-    lettuce { # configuration to fetch/store otoroshi state from a redis datastore using the lettuce driver (the next default one)
-      connection = ${?REDIS_LETTUCE_CONNECTION}
-      connection = ${?OTOROSHI_REDIS_LETTUCE_CONNECTION}
-      uri =  ${?REDIS_LETTUCE_URI}
-      uri =  ${?OTOROSHI_REDIS_LETTUCE_URI}
-      uri =  ${?REDIS_URL}
-      uri =  ${?OTOROSHI_REDIS_URL}
-      urisStr = ${?REDIS_LETTUCE_URIS}
-      urisStr = ${?OTOROSHI_REDIS_LETTUCE_URIS}
-      readFrom = ${?REDIS_LETTUCE_READ_FROM}
-      readFrom = ${?OTOROSHI_REDIS_LETTUCE_READ_FROM}
-      startTLS = ${?REDIS_LETTUCE_START_TLS}
-      startTLS = ${?OTOROSHI_REDIS_LETTUCE_START_TLS}
-      verifyPeers = ${?REDIS_LETTUCE_VERIFY_PEERS}
-      verifyPeers = ${?OTOROSHI_REDIS_LETTUCE_VERIFY_PEERS}
-    }
-  }
-  inmemory { # configuration to fetch/store otoroshi state in memory
-    windowSize = ${?INMEMORY_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_INMEMORY_WINDOW_SIZE}
-    experimental = ${?INMEMORY_EXPERIMENTAL_STORE}
-    experimental = ${?OTOROSHI_INMEMORY_EXPERIMENTAL_STORE}
-    optimized = ${?INMEMORY_OPTIMIZED}
-    optimized = ${?OTOROSHI_INMEMORY_OPTIMIZED}
-    modern =  ${?INMEMORY_MODERN}
-    modern =  ${?OTOROSHI_INMEMORY_MODERN}
-  }
-  filedb { # configuration to fetch/store otoroshi state from a file
-    windowSize = ${?FILEDB_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_FILEDB_WINDOW_SIZE}
-    path = ${?FILEDB_PATH}
-    path = ${?OTOROSHI_FILEDB_PATH}
-  }
-  httpdb { # configuration to fetch/store otoroshi state from an http endpoint
-    headers = {}
-  }
-  s3db { # configuration to fetch/store otoroshi state from a S3 bucket
-    bucket = ${?OTOROSHI_DB_S3_BUCKET}
-    endpoint = ${?OTOROSHI_DB_S3_ENDPOINT}
-    region = ${?OTOROSHI_DB_S3_REGION}
-    access = ${?OTOROSHI_DB_S3_ACCESS}
-    secret = ${?OTOROSHI_DB_S3_SECRET}
-    key = ${?OTOROSHI_DB_S3_KEY}
-    chunkSize = ${?OTOROSHI_DB_S3_CHUNK_SIZE}
-    v4auth = ${?OTOROSHI_DB_S3_V4_AUTH}
-    writeEvery = ${?OTOROSHI_DB_S3_WRITE_EVERY} # write interval
-    acl = ${?OTOROSHI_DB_S3_ACL}
-  }
-  pg { # postrgesql settings. everything possible with the client
-    uri = ${?PG_URI}
-    uri = ${?OTOROSHI_PG_URI}
-    uri = ${?POSTGRESQL_ADDON_URI}
-    uri = ${?OTOROSHI_POSTGRESQL_ADDON_URI}
-    poolSize = ${?PG_POOL_SIZE}
-    poolSize = ${?OTOROSHI_PG_POOL_SIZE}
-    port = ${?PG_PORT}
-    port = ${?OTOROSHI_PG_PORT}
-    host = ${?PG_HOST}
-    host = ${?OTOROSHI_PG_HOST}
-    database = ${?PG_DATABASE}
-    database = ${?OTOROSHI_PG_DATABASE}
-    user = ${?PG_USER}
-    user = ${?OTOROSHI_PG_USER}
-    password = ${?PG_PASSWORD}
-    password = ${?OTOROSHI_PG_PASSWORD}
-    logQueries = ${?PG_DEBUG_QUERIES}
-    logQueries = ${?OTOROSHI_PG_DEBUG_QUERIES}
-    avoidJsonPath = ${?PG_AVOID_JSON_PATH}
-    avoidJsonPath = ${?OTOROSHI_PG_AVOID_JSON_PATH}
-    optimized = ${?PG_OPTIMIZED}
-    optimized = ${?OTOROSHI_PG_OPTIMIZED}
-    connect-timeout = ${?PG_CONNECT_TIMEOUT}
-    connect-timeout = ${?OTOROSHI_PG_CONNECT_TIMEOUT}
-    idle-timeout = ${?PG_IDLE_TIMEOUT}
-    idle-timeout = ${?OTOROSHI_PG_IDLE_TIMEOUT}
-    log-activity = ${?PG_LOG_ACTIVITY}
-    log-activity = ${?OTOROSHI_PG_LOG_ACTIVITY}
-    pipelining-limit = ${?PG_PIPELINING_LIMIT}
-    pipelining-limit = ${?OTOROSHI_PG_PIPELINING_LIMIT}
-    ssl {
-      enabled = ${?PG_SSL_ENABLED}
-      enabled = ${?OTOROSHI_PG_SSL_ENABLED}
-      mode = ${?PG_SSL_MODE}
-      mode = ${?OTOROSHI_PG_SSL_MODE}
-      trusted-cert-path = ${?PG_SSL_TRUSTED_CERT_PATH}
-      trusted-cert-path = ${?OTOROSHI_PG_SSL_TRUSTED_CERT_PATH}
-      trusted-cert = ${?PG_SSL_TRUSTED_CERT}
-      trusted-cert = ${?OTOROSHI_PG_SSL_TRUSTED_CERT}
-      client-cert-path = ${?PG_SSL_CLIENT_CERT_PATH}
-      client-cert-path = ${?OTOROSHI_PG_SSL_CLIENT_CERT_PATH}
-      client-cert = ${?PG_SSL_CLIENT_CERT}
-      client-cert = ${?OTOROSHI_PG_SSL_CLIENT_CERT}
-      trust-all = ${?PG_SSL_TRUST_ALL}
-      trust-all = ${?OTOROSHI_PG_SSL_TRUST_ALL}
-    }
-  }
-  cassandra { # cassandra settings. everything possible with the client
-    windowSize = ${?CASSANDRA_WINDOW_SIZE}
-    windowSize = ${?OTOROSHI_CASSANDRA_WINDOW_SIZE}
-    host = ${?CASSANDRA_HOST}
-    host = ${?OTOROSHI_CASSANDRA_HOST}
-    port = ${?CASSANDRA_PORT}
-    port = ${?OTOROSHI_CASSANDRA_PORT}
-    replicationFactor = ${?CASSANDRA_REPLICATION_FACTOR}
-    replicationFactor = ${?OTOROSHI_CASSANDRA_REPLICATION_FACTOR}
-    replicationOptions = ${?CASSANDRA_REPLICATION_OPTIONS}
-    replicationOptions = ${?OTOROSHI_CASSANDRA_REPLICATION_OPTIONS}
-    durableWrites = ${?CASSANDRA_DURABLE_WRITES}
-    durableWrites = ${?OTOROSHI_CASSANDRA_DURABLE_WRITES}
-    basic.contact-points = [ ${app.cassandra.host}":"${app.cassandra.port} ]
-    basic.session-name = ${?OTOROSHI_CASSANDRA_SESSION_NAME}
-    basic.session-keyspace = ${?OTOROSHI_CASSANDRA_SESSION_KEYSPACE}
-    basic.request {
-      consistency = ${?OTOROSHI_CASSANDRA_CONSISTENCY}
-      page-size = ${?OTOROSHI_CASSANDRA_PAGE_SIZE}
-      serial-consistency = ${?OTOROSHI_CASSANDRA_SERIAL_CONSISTENCY}
-      default-idempotence = ${?OTOROSHI_CASSANDRA_DEFAULT_IDEMPOTENCE}
-    }
-    basic.load-balancing-policy {
-      local-datacenter = ${?OTOROSHI_CASSANDRA_LOCAL_DATACENTER}
-    }
-    basic.cloud {
-    }
-    basic.application {
-    }
-    basic.graph {
-    }
-    advanced.connection {
-      set-keyspace-timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      pool {
-        local {
-        }
-        remote {
-        }
-      }
-    }
-    advanced.reconnection-policy {
-    }
-    advanced.retry-policy {
-    }
-    advanced.speculative-execution-policy {
-    }
-    advanced.auth-provider {
-      username = ${?CASSANDRA_USERNAME}
-      username = ${?OTOROSHI_CASSANDRA_USERNAME}
-      password = ${?CASSANDRA_PASSWORD}
-      password = ${?OTOROSHI_CASSANDRA_PASSWORD}
-      authorization-id = ${?OTOROSHI_CASSANDRA_AUTHORIZATION_ID}
-      # login-configuration {
-      # }
-      # sasl-properties {
-      # }
-    }
-    advanced.ssl-engine-factory {
-    }
-    advanced.timestamp-generator {
-      drift-warning {
-      }
-    }
-    advanced.request-tracker {
-      logs {
-        slow {
-        }
-      }
-    }
-    advanced.throttler {
-    }
-    advanced.address-translator {
-    }
-    advanced.protocol {
-      version = ${?OTOROSHI_CASSANDRA_PROTOCOL_VERSION}
-      compression = ${?OTOROSHI_CASSANDRA_PROTOCOL_COMPRESSION}
-    }
-    advanced.request {
-      trace {
-      }
-    }
-    advanced.graph {
-      paging-options {
-        page-size = ${datastax-java-driver.advanced.continuous-paging.page-size}
-        max-pages = ${datastax-java-driver.advanced.continuous-paging.max-pages}
-        max-pages-per-second = ${datastax-java-driver.advanced.continuous-paging.max-pages-per-second}
-        max-enqueued-pages = ${datastax-java-driver.advanced.continuous-paging.max-enqueued-pages}
-      }
-    }
-    advanced.continuous-paging {
-      page-size = ${datastax-java-driver.basic.request.page-size}
-      timeout {
-      }
-    }
-    advanced.monitor-reporting {
-    }
-    advanced.metrics {
-      session {
-        cql-requests {
-        }
-        throttling.delay {
-        }
-        continuous-cql-requests {
-        }
-        graph-requests {
-        }
-      }
-      node {
-        cql-messages {
-        }
-        graph-messages {
-        }
-      }
-    }
-    advanced.socket {
-    }
-    advanced.heartbeat {
-      timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-    }
-    advanced.metadata {
-      topology-event-debouncer {
-      }
-      schema {
-        request-timeout = ${datastax-java-driver.basic.request.timeout}
-        request-page-size = ${datastax-java-driver.basic.request.page-size}
-        debouncer {
-        }
-      }
-    }
-    advanced.control-connection {
-      timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      schema-agreement {
-      }
-    }
-    advanced.prepared-statements {
-      reprepare-on-up {
-        timeout = ${datastax-java-driver.advanced.connection.init-query-timeout}
-      }
-    }
-    advanced.netty {
-      io-group {
-        shutdown {quiet-period = 2, timeout = 15, unit = SECONDS}
-      }
-      admin-group {
-        shutdown {quiet-period = 2, timeout = 15, unit = SECONDS}
-      }
-      timer {
-      }
-    }
-    advanced.coalescer {
-    }
-  }
-  actorsystems {
-    otoroshi {
-      akka { # otoroshi actorsystem configuration
-        version = ${akka.version}
-        default-dispatcher {
-          fork-join-executor {
-            parallelism-factor = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_FACTOR}
-            parallelism-min = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_MIN}
-            parallelism-max = ${?OTOROSHI_CORE_DISPATCHER_PARALLELISM_MAX}
-            task-peeking-mode = ${?OTOROSHI_CORE_DISPATCHER_TASK_PEEKING_MODE}
-          }
-          throughput = ${?OTOROSHI_CORE_DISPATCHER_THROUGHPUT}
-        }
-        http {
-          parsing {
-            max-chunk-size             = ${?AKKA_HTTP_CLIENT_MAX_CHUNK_SIZE}
-            max-chunk-size             = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_CHUNK_SIZE}
-            max-content-length         = ${?AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT}
-            max-content-length         = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT}
-            max-to-strict-bytes        = ${?AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES}
-            max-to-strict-bytes        = ${?OTOROSHI_AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES}
-          }
-        }
-      }
-    }
-    datastore {
-      akka {
-        version = ${akka.version}
-        default-dispatcher {
-          fork-join-executor {
-          }
-        }
-      }
-    }
-  }
-}
-otoroshi {
-  domain = ${?app.domain}
-  maintenanceMode = ${?OTOROSHI_MAINTENANCE_MODE_ENABLED} # enable global maintenance mode
-  secret = ${?OTOROSHI_SECRET}  # the secret used to sign sessions
-  admin-api-secret = ${?OTOROSHI_ADMIN_API_SECRET}  # the secret for admin api
-  next {
-    state-sync-interval = ${?OTOROSHI_NEXT_STATE_SYNC_INTERVAL}
-    export-reporting = ${?OTOROSHI_NEXT_EXPORT_REPORTING}
-    monitor-proxy-state-size = ${?OTOROSHI_NEXT_MONITOR_PROXY_STATE_SIZE}
-    monitor-datastore-size = ${?OTOROSHI_NEXT_MONITOR_DATASTORE_SIZE}
-    plugins {
-      merge-sync-steps = ${?OTOROSHI_NEXT_PLUGINS_MERGE_SYNC_STEPS}
-      apply-legacy-checks = ${?OTOROSHI_NEXT_PLUGINS_APPLY_LEGACY_CHECKS}
-    }
-  }
-  options {
-    bypassUserRightsCheck = ${?OTOROSHI_OPTIONS_BYPASSUSERRIGHTSCHECK}
-    emptyContentLengthIsChunked = ${?OTOROSHI_OPTIONS_EMPTYCONTENTLENGTHISCHUNKED}
-    detectApiKeySooner = ${?OTOROSHI_OPTIONS_DETECTAPIKEYSOONER}
-    sendClientChainAsPem = ${?OTOROSHI_OPTIONS_SENDCLIENTCHAINASPEM}
-    useOldHeadersComposition = ${?OTOROSHI_OPTIONS_USEOLDHEADERSCOMPOSITION}
-    manualDnsResolve = ${?OTOROSHI_OPTIONS_MANUALDNSRESOLVE}
-    useEventStreamForScriptEvents = ${?OTOROSHI_OPTIONS_USEEVENTSTREAMFORSCRIPTEVENTS}
-    trustXForwarded = ${?OTOROSHI_OPTIONS_TRUST_XFORWARDED}
-    disableFunnyLogos = ${?OTOROSHI_OPTIONS_DISABLE_FUNNY_LOGOS}
-    staticExposedDomain = ${?OTOROSHI_OPTIONS_STATIC_EXPOSED_DOMAIN}
-  }
-  backoffice {
-    flags {
-      useAkkaHttpClient = ${?OTOROSHI_BACKOFFICE_FLAGS_USE_AKKA_HTTP_CLIENT}
-      logUrl = ${?OTOROSHI_BACKOFFICE_FLAGS_LOG_URL}
-      requestTimeout = ${?OTOROSHI_BACKOFFICE_FLAGS_REQUEST_TIMEOUT}
-    }
-  }
-  sessions {
-    secret = ${otoroshi.secret}
-    secret = ${?OTOROSHI_SESSIONS_SECRET}
-  }
-  cache {
-    enabled = ${?USE_CACHE}
-    enabled = ${?OTOROSHI_USE_CACHE}
-    enabled = ${?OTOROSHI_ENTITIES_CACHE_ENABLED}
-    ttl = ${?OTOROSHI_ENTITIES_CACHE_TTL}
-  }
-  metrics {
-    enabled = ${?OTOROSHI_METRICS_ENABLED}
-    every = ${?OTOROSHI_METRICS_EVERY}
-    accessKey = ${?app.health.accessKey}
-    accessKey = ${?OTOROSHI_app.health.accessKey}
-    accessKey = ${?OTOROSHI_METRICS_ACCESS_KEY}
-  }
-  plugins {
-    packagesStr = ${?OTOROSHI_PLUGINS_SCAN_PACKAGES}
-    print = ${?OTOROSHI_PLUGINS_PRINT}
-  }
-  scripts {
-    enabled = ${?OTOROSHI_SCRIPTS_ENABLED} # enable scripts
-    static { # settings for statically enabled script/plugins
-      enabled = ${?OTOROSHI_SCRIPTS_STATIC_ENABLED}
-      transformersRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_TRANSFORMER_REFS}
-      transformersConfig = {}
-      transformersConfigStr= ${?OTOROSHI_SCRIPTS_STATIC_TRANSFORMER_CONFIG}
-      validatorRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_VALIDATOR_REFS}
-      validatorConfig = {}
-      validatorConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_VALIDATOR_CONFIG}
-      preRouteRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_PRE_ROUTE_REFS}
-      preRouteConfig = {}
-      preRouteConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_PRE_ROUTE_CONFIG}
-      sinkRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_SINK_REFS}
-      sinkConfig = {}
-      sinkConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_SINK_CONFIG}
-      jobsRefsStr = ${?OTOROSHI_SCRIPTS_STATIC_JOBS_REFS}
-      jobsConfig = {}
-      jobsConfigStr = ${?OTOROSHI_SCRIPTS_STATIC_JOBS_CONFIG}
-    }
-  }
-  tls = ${otoroshi.ssl}
-  ssl {
-    cacert {
-    }
-    fromOutside {
-      clientAuth = ${?SSL_OUTSIDE_CLIENT_AUTH}
-      clientAuth = ${?OTOROSHI_SSL_OUTSIDE_CLIENT_AUTH}
-    }
-    trust {
-      all = ${?OTOROSHI_SSL_TRUST_ALL}
-    }
-    initialCacert = ${?CLUSTER_WORKER_INITIAL_CACERT}
-    initialCacert = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CACERT}
-    initialCacert = ${?INITIAL_CACERT}
-    initialCacert = ${?OTOROSHI_INITIAL_CACERT}
-    initialCert = ${?CLUSTER_WORKER_INITIAL_CERT}
-    initialCert = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CERT}
-    initialCert = ${?INITIAL_CERT}
-    initialCert = ${?OTOROSHI_INITIAL_CERT}
-    initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY}
-    initialCertKey = ${?OTOROSHI_CLUSTER_WORKER_INITIAL_CERT_KEY}
-    initialCertKey = ${?INITIAL_CERT_KEY}
-    initialCertKey = ${?OTOROSHI_INITIAL_CERT_KEY}
-  }
-  cluster {
-    mode = ${?CLUSTER_MODE} # can be "off", "leader", "worker"
-    mode = ${?OTOROSHI_CLUSTER_MODE} # can be "off", "leader", "worker"
-    compression = ${?CLUSTER_COMPRESSION} # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9
-    compression = ${?OTOROSHI_CLUSTER_COMPRESSION} # compression of the data sent between leader cluster and worker cluster. From -1 (disabled) to 9
-    retryDelay = ${?CLUSTER_RETRY_DELAY} # the delay before retrying a request to leader
-    retryDelay = ${?OTOROSHI_CLUSTER_RETRY_DELAY} # the delay before retrying a request to leader
-    retryFactor = ${?CLUSTER_RETRY_FACTOR} # the retry factor to avoid high load on failing nodes
-    retryFactor = ${?OTOROSHI_CLUSTER_RETRY_FACTOR} # the retry factor to avoid high load on failing nodes
-    selfAddress = ${?CLUSTER_SELF_ADDRESS} # the cluster slefAddress
-    selfAddress = ${?OTOROSHI_CLUSTER_SELF_ADDRESS} # the cluster selfAddress
-    autoUpdateState = ${?CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (more efficient
-    autoUpdateState = ${?OTOROSHI_CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (more efficient
-    mtls {
-      enabled = ${?CLUSTER_MTLS_ENABLED}  # enable mtls
-      enabled = ${?OTOROSHI_CLUSTER_MTLS_ENABLED}  # enable mtls
-      loose = ${?CLUSTER_MTLS_LOOSE}  # loose verification
-      loose = ${?OTOROSHI_CLUSTER_MTLS_LOOSE}  # loose verification
-      trustAll = ${?CLUSTER_MTLS_TRUST_ALL} # trust any CA
-      trustAll = ${?OTOROSHI_CLUSTER_MTLS_TRUST_ALL} # trust any CA
-    }
-    leader {
-      name = ${?CLUSTER_LEADER_NAME} # the leader name
-      name = ${?OTOROSHI_CLUSTER_LEADER_NAME} # the leader name
-      url = ${?CLUSTER_LEADER_URL} # the leader url
-      url = ${?OTOROSHI_CLUSTER_LEADER_URL} # the leader url
-      host = ${?CLUSTER_LEADER_HOST} # the leaders api hostname
-      host = ${?OTOROSHI_CLUSTER_LEADER_HOST} # the leaders api hostname
-      clientId = ${?CLUSTER_LEADER_CLIENT_ID} # the leaders apikey id to access otoroshi admin api
-      clientId = ${?OTOROSHI_CLUSTER_LEADER_CLIENT_ID} # the leaders apikey id to access otoroshi admin api
-      clientSecret = ${?CLUSTER_LEADER_CLIENT_SECRET} # the leaders apikey secret to access otoroshi admin api
-      clientSecret = ${?OTOROSHI_CLUSTER_LEADER_CLIENT_SECRET} # the leaders apikey secret to access otoroshi admin api
-      groupingBy = ${?CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state
-      groupingBy = ${?OTOROSHI_CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state
-      cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache
-      cacheStateFor = ${?OTOROSHI_CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache
-      stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose
-      stateDumpPath = ${?OTOROSHI_CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose
-    }
-    worker {
-      name = ${?CLUSTER_WORKER_NAME} # the workers name
-      name = ${?OTOROSHI_CLUSTER_WORKER_NAME} # the workers name
-      retries = ${?CLUSTER_WORKER_RETRIES} # the number of retries when pushing quotas/pulling state
-      retries = ${?OTOROSHI_CLUSTER_WORKER_RETRIES} # the number of retries when pushing quotas/pulling state
-      timeout = ${?CLUSTER_WORKER_TIMEOUT} # the workers timeout when interacting with leaders
-      timeout = ${?OTOROSHI_CLUSTER_WORKER_TIMEOUT} # the workers timeout when interacting with leaders
-      tenantsStr = ${?CLUSTER_WORKER_TENANTS} # the list (coma separated) of organization served by this worker. If none, it's all
-      tenantsStr = ${?OTOROSHI_CLUSTER_WORKER_TENANTS} # the list (coma separated) of organization served by this worker. If none, it's all
-      dbpath = ${?CLUSTER_WORKER_DB_PATH} # state dump path for debugging purpose
-      dbpath = ${?OTOROSHI_CLUSTER_WORKER_DB_PATH} # state dump path for debugging purpose
-      dataStaleAfter = ${?CLUSTER_WORKER_DATA_STALE_AFTER} # the amount of time needed to consider state is stale
-      dataStaleAfter = ${?OTOROSHI_CLUSTER_WORKER_DATA_STALE_AFTER} # the amount of time needed to consider state is stale
-      swapStrategy = ${?CLUSTER_WORKER_SWAP_STRATEGY} # the internal memory store strategy, can be Replace or Merge
-      swapStrategy = ${?OTOROSHI_CLUSTER_WORKER_SWAP_STRATEGY} # the internal memory store strategy, can be Replace or Merge
-      modern = ${?CLUSTER_WORKER_STORE_MODERN}
-      modern = ${?OTOROSHI_CLUSTER_WORKER_STORE_MODERN}
-      state {
-        retries = ${otoroshi.cluster.worker.retries} # the number of retries when pulling state
-        retries = ${?CLUSTER_WORKER_STATE_RETRIES} # the number of retries when pulling state
-        retries = ${?OTOROSHI_CLUSTER_WORKER_STATE_RETRIES} # the number of retries when pulling state
-        pollEvery = ${?CLUSTER_WORKER_POLL_EVERY} # polling interval
-        pollEvery = ${?OTOROSHI_CLUSTER_WORKER_POLL_EVERY} # polling interval
-        timeout = ${otoroshi.cluster.worker.timeout} # the workers timeout when polling state
-        timeout = ${?CLUSTER_WORKER_POLL_TIMEOUT} # the workers timeout when polling state
-        timeout = ${?OTOROSHI_CLUSTER_WORKER_POLL_TIMEOUT} # the workers timeout when polling state
-      }
-      quotas {
-        retries = ${otoroshi.cluster.worker.retries} # the number of retries when pushing quotas
-        retries = ${?CLUSTER_WORKER_QUOTAS_RETRIES} # the number of retries when pushing quotas
-        retries = ${?OTOROSHI_CLUSTER_WORKER_QUOTAS_RETRIES} # the number of retries when pushing quotas
-        pushEvery = ${?CLUSTER_WORKER_PUSH_EVERY} # pushing interval
-        pushEvery = ${?OTOROSHI_CLUSTER_WORKER_PUSH_EVERY} # pushing interval
-        timeout = ${otoroshi.cluster.worker.timeout} # the workers timeout when pushing quotas
-        timeout = ${?CLUSTER_WORKER_PUSH_TIMEOUT} # the workers timeout when pushing quotas
-        timeout = ${?OTOROSHI_CLUSTER_WORKER_PUSH_TIMEOUT} # the workers timeout when pushing quotas
-      }
-    }
-    analytics { # settings for the analytics actor system which is separated from otoroshi default one for performance reasons
-      pressure {
-        enabled = ${?OTOROSHI_ANALYTICS_PRESSURE_ENABLED}
-      }
-      actorsystem {
-        akka {
-          version = ${akka.version}
-          default-dispatcher {
-            fork-join-executor {
-            }
-          }
-          # http {
-          #   parsing {
-          #     max-chunk-size             = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CHUNK_SIZE}
-          #     max-chunk-size             = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_CHUNK_SIZE}
-          #     max-content-length         = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT}
-          #     max-content-length         = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT}
-          #     max-to-strict-bytes        = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_TO_STRICT_BYTES}
-          #     max-to-strict-bytes        = ${?OTOROSHI_AKKA_HTTP_CLIENT_ANALYTICS_MAX_TO_STRICT_BYTES}
-          #   }
-          # }
-        }
-      }
-    }
-  }
-  headers { # the default headers value for specific otoroshi headers
-  }
-  requests {
-    validate = ${?OTOROSHI_REQUESTS_VALIDATE}
-    maxUrlLength = ${akka.http.parsing.max-uri-length}
-    maxCookieLength = ${akka.http.parsing.max-header-value-length}
-    maxHeaderNameLength = ${akka.http.parsing.max-header-name-length}
-    maxHeaderValueLength = ${akka.http.parsing.max-header-value-length}
-  }
-  jmx {
-    enabled = ${?OTOROSHI_JMX_ENABLED}
-    port = ${?OTOROSHI_JMX_PORT}
-  }
-  loggers {
-  }
-  provider {
-    dashboardUrl = ${?OTOROSHI_PROVIDER_DASHBOARD_URL}
-    jsUrl = ${?OTOROSHI_PROVIDER_JS_URL}
-    cssUrl = ${?OTOROSHI_PROVIDER_CSS_URL}
-    secret = ${?OTOROSHI_PROVIDER_SECRET}
-    title = ${?OTOROSHI_PROVIDER_TITLE}
-  }
-  healthcheck {
-    workers = ${?OTOROSHI_HEALTHCHECK_WORKERS}
-    block-on-red = ${?OTOROSHI_HEALTHCHECK_BLOCK_ON_RED}
-    block-on-red = ${?OTOROSHI_HEALTHCHECK_BLOCK_ON_500}
-    ttl = ${?OTOROSHI_HEALTHCHECK_TTL}
-    ttl-only = ${?OTOROSHI_HEALTHCHECK_TTL_ONLY}
-  }
-  vaults {
-    enabled = ${?OTOROSHI_VAULTS_ENABLED}
-    secrets-ttl = ${?OTOROSHI_VAULTS_SECRETS_TTL}
-    cached-secrets = ${?OTOROSHI_VAULTS_CACHED_SECRETS}
-    read-ttl = ${?OTOROSHI_VAULTS_READ_TTL}
-    parallel-fetchs = ${?OTOROSHI_VAULTS_PARALLEL_FETCHS}
-    leader-fetch-only = ${?OTOROSHI_VAULTS_LEADER_FETCH_ONLY}
-    env {
-      prefix = ${?OTOROSHI_VAULTS_ENV_PREFIX}
-    }
-    # hashicorpvault {
-    # }
-  }
-}
-http.port = ${?otoroshi.http.port}     # the main http port for the otoroshi server
-http.port = ${?PORT}                   # the main http port for the otoroshi server
-http.port = ${?OTOROSHI_PORT}                   # the main http port for the otoroshi server
-http.port = ${?OTOROSHI_HTTP_PORT}                   # the main http port for the otoroshi server
-play.server.http.port = ${http.port}   # the main http port for the otoroshi server
-play.server.http.port = ${?PORT}       # the main http port for the otoroshi server
-play.server.http.port = ${?OTOROSHI_PORT}       # the main http port for the otoroshi server
-play.server.http.port = ${?OTOROSHI_HTTP_PORT}       # the main http port for the otoroshi server
-https.port = ${?otoroshi.https.port}   # the main https port for the otoroshi server
-https.port = ${?HTTPS_PORT}            # the main https port for the otoroshi server
-https.port = ${?OTOROSHI_HTTPS_PORT}            # the main https port for the otoroshi server
-play.server.https.keyStoreDumpPath = ${?HTTPS_KEYSTORE_DUMP_PATH}           # the file path where the TLSContext will be dumped (for debugging purposes only)
-play.server.https.keyStoreDumpPath = ${?OTOROSHI_HTTPS_KEYSTORE_DUMP_PATH}           # the file path where the TLSContext will be dumped (for debugging purposes only)
-play.http.secret.key = ${otoroshi.secret}       # the secret used to signed session cookies                       
-play.http.secret.key = ${?PLAY_CRYPTO_SECRET}   # the secret used to signed session cookies
-play.http.secret.key = ${?OTOROSHI_CRYPTO_SECRET}   # the secret used to signed session cookies
-play.server.http.idleTimeout = ${?PLAY_SERVER_IDLE_TIMEOUT}       # the default server idle timeout
-play.server.http.idleTimeout = ${?OTOROSHI_SERVER_IDLE_TIMEOUT}       # the default server idle timeout
-play.server.akka.requestTimeout = ${?PLAY_SERVER_REQUEST_TIMEOUT} # the default server idle timeout (for akka server specifically)
-play.server.akka.requestTimeout = ${?OTOROSHI_SERVER_REQUEST_TIMEOUT} # the default server idle timeout (for akka server specifically)
-http2.enabled = ${?otoroshi.http2.enabled}
-http2.enabled = ${?HTTP2_ENABLED}  # enable HTTP2 support
-http2.enabled = ${?OTOROSHI_HTTP2_ENABLED}  # enable HTTP2 support
-play.server.https.keyStore.path=${?HTTPS_KEYSTORE_PATH}         # settings for the default server keystore
-play.server.https.keyStore.path=${?OTOROSHI_HTTPS_KEYSTORE_PATH}         # settings for the default server keystore
-play.server.https.keyStore.type=${?HTTPS_KEYSTORE_TYPE}         # settings for the default server keystore
-play.server.https.keyStore.type=${?OTOROSHI_HTTPS_KEYSTORE_TYPE}         # settings for the default server keystore
-play.server.https.keyStore.password=${?HTTPS_KEYSTORE_PASSWORD} # settings for the default server keystore
-play.server.https.keyStore.password=${?OTOROSHI_HTTPS_KEYSTORE_PASSWORD} # settings for the default server keystore
-play.server.https.keyStore.algorithm=${?HTTPS_KEYSTORE_ALGO}    # settings for the default server keystore
-play.server.https.keyStore.algorithm=${?OTOROSHI_HTTPS_KEYSTORE_ALGO}    # settings for the default server keystore
-play.http {
-  session {
-    secure = ${?SESSION_SECURE_ONLY}  # the cookie for otoroshi backoffice should be exhanged over https only
-    secure = ${?OTOROSHI_SESSION_SECURE_ONLY}  # the cookie for otoroshi backoffice should be exhanged over https only
-    maxAge = ${?SESSION_MAX_AGE}      # the cookie for otoroshi backoffice max age
-    maxAge = ${?OTOROSHI_SESSION_MAX_AGE}      # the cookie for otoroshi backoffice max age
-    # domain = "."${?app.domain}         # the cookie for otoroshi backoffice domain
-    domain = "."${otoroshi.domain}    # the cookie for otoroshi backoffice domain
-    domain = ${?SESSION_DOMAIN}       # the cookie for otoroshi backoffice domain
-    domain = ${?OTOROSHI_SESSION_DOMAIN}       # the cookie for otoroshi backoffice domain
-    cookieName = ${?SESSION_NAME}     # the cookie for otoroshi backoffice name
-    cookieName = ${?OTOROSHI_SESSION_NAME}     # the cookie for otoroshi backoffice name
-  }
-}
-akka { # akka specific configuration
-  actor {
-    default-dispatcher {
-      fork-join-executor {     
-        parallelism-factor = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_FACTOR}
-        parallelism-min = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_MIN}
-        parallelism-max = ${?OTOROSHI_AKKA_DISPATCHER_PARALLELISM_MAX}
-        task-peeking-mode = ${?OTOROSHI_AKKA_DISPATCHER_TASK_PEEKING_MODE}
-      }
-      throughput = ${?OTOROSHI_AKKA_DISPATCHER_THROUGHPUT}
-    }
-  }
-  http {
-    server {
-      socket-options {
-      }
-      http2 {
-      }
-    }
-    client {
-      socket-options {
-      }
-    }
-    host-connection-pool {
-      client {
-        socket-options {
-        }
-      }
-    }
-    parsing {
-      max-chunk-size             = ${?AKKA_HTTP_SERVER_MAX_CHUNK_SIZE}
-      max-chunk-size             = ${?OTOROSHI_AKKA_HTTP_SERVER_MAX_CHUNK_SIZE}
-      max-content-length         = ${?AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT}
-      max-content-length         = ${?OTOROSHI_AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT}
-    }
-  }
-}
- -
- -
- -
-
- -
- -
- - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - diff --git a/docs/manual/js/cc.js b/docs/manual/js/cc.js deleted file mode 100644 index de76ca7b4e..0000000000 --- a/docs/manual/js/cc.js +++ /dev/null @@ -1,145 +0,0 @@ -$(function() { - - function dec2hex (dec) { - return dec < 10 - ? '0' + String(dec) - : dec.toString(16) - } - - function generateSecret(len) { - var arr = new Uint8Array((len || 40) / 2) - window.crypto.getRandomValues(arr) - return Array.from(arr, dec2hex).join('') - } - - var names = { - 'app_domain': "Domain name", - 'app_storage': "Otoroshi storage", - 'init_login': "User login", - 'init_pwd': "User password" - }; - - var orgaId = generateSecret(16); - - var state = { - 'admin_api_client_id': generateSecret(32), - 'admin_api_client_secret': generateSecret(32), - 'admin_api_group': generateSecret(32), - 'admin_api_service_id': generateSecret(32), - 'shared_key': generateSecret(32), - 'crypto_secret': generateSecret(32), - 'oto_secret': generateSecret(32), - 'session_name': `oto-session-${generateSecret(8)}`, - 'app_domain': 'cleverapps.io', - 'app_storage': 'inmemory', - 'app_scheme': 'https', - 'app_backoffice_subdomain': `otoroshi-${orgaId}`, - 'app_api_subdomain': `otoroshi-api-${orgaId}`, - 'app_api_int_subdomain': `otoroshi-api-int-${orgaId}`, - 'app_papps_subdomain': `otoroshi-papps-${orgaId}`, - 'init_login': `${orgaId}@otoroshi.io`, - 'init_pwd': generateSecret(32), - 'version': '1.4.22', - }; - - fetch('https://updates.otoroshi.io/api/versions/latest', { - method: 'GET', - cors: true - }).then(r => r.json()).then(r => { - state.version = r.version_raw; - render(); - }); - - function render() { - var template = ` - ${Object.keys(names).map(name => `${names[name]} `).join('\n')} -
- -
-
-Your otoroshi instance will be located at

- -https://${state.app_backoffice_subdomain}.${state.app_domain}

- -You can connect on your instance with the following credentials

- -${state.init_login} / ${state.init_pwd}

- -You can use your instance api at

- -https://${state.app_api_subdomain}.${state.app_domain}

- -with the following authorization header

- -Authorization: Basic ${btoa(`${state.admin_api_client_id}:${state.admin_api_client_secret}`)}

-
- -copy the following environment variables in you clevercloud app in expert mode :

-
-ADMIN_API_CLIENT_ID=${state.admin_api_client_id}
-ADMIN_API_CLIENT_SECRET=${state.admin_api_client_secret}
-ADMIN_API_GROUP=${state.admin_api_group}
-ADMIN_API_SERVICE_ID=${state.admin_api_service_id}
-CLAIM_SHAREDKEY=${state.shared_key}
-OTOROSHI_INITIAL_ADMIN_LOGIN=${state.init_login}
-OTOROSHI_INITIAL_ADMIN_PASSWORD=${state.init_pwd}
-OTOROSHI_SECRET=${state.oto_secret}
-PLAY_CRYPTO_SECRET=${state.crypto_secret}
-SESSION_NAME=${state.session_name}
-APP_DOMAIN=${state.app_domain}
-APP_BACKOFFICE_SUBDOMAIN=${state.app_backoffice_subdomain}
-APP_PRIVATEAPPS_SUBDOMAIN=${state.app_papps_subdomain}
-ADMIN_API_TARGET_SUBDOMAIN=${state.app_api_int_subdomain}
-ADMIN_API_EXPOSED_SUBDOMAIN=${state.app_api_subdomain}
-APP_ENV=prod
-APP_STORAGE=${state.app_storage}
-APP_ROOT_SCHEME=https
-CC_OTO_VERSION=curl https://updates.otoroshi.io/api/versions/latest | jq -r '.version_raw'; 
-CC_PRE_BUILD_HOOK=curl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/${state.version}/otoroshi.jar'
-CC_JAR_PATH=./otoroshi.jar
-CC_JAVA_VERSION=11
-PORT=8080
-SESSION_DOMAIN=.${state.app_domain}
-SESSION_MAX_AGE=604800000
-SESSION_SECURE_ONLY=true
-USER_AGENT=otoroshi-${orgaId}
-MAX_EVENTS_SIZE=1
-WEBHOOK_SIZE=100
-APP_BACKOFFICE_SESSION_EXP=86400000
-APP_PRIVATEAPPS_SESSION_EXP=86400000
-ENABLE_METRICS=true
-OTOROSHI_ANALYTICS_PRESSURE_ENABLED=true
-USE_CACHE=true
-` - var int = $('#clevercloud-envvars-internals'); - if (int.length) { - $('#clevercloud-envvars-internals').html(template); - } else { - $('#clevercloud-envvars').html('
' + template + '
'); - } - } - - - function hook() { - if ($('#clevercloud-envvars').length) { - render(); - - function fire(e) { - var name = e.target.name; - var value = e.target.value; - state[name] = value; - render(); - } - - $("#clevercloud-envvars").on('change', "input[type='text']", fire); - $("#clevercloud-envvars input[type='text']").change(fire); - $("#clevercloud-envvars").on('click', '#refresh', function() { - render(); - }); - } else { - console.log('not found !') - } - } - - hook() -}); \ No newline at end of file diff --git a/docs/manual/js/expression-language.js b/docs/manual/js/expression-language.js deleted file mode 100644 index 8617d07221..0000000000 --- a/docs/manual/js/expression-language.js +++ /dev/null @@ -1,391 +0,0 @@ - -document.addEventListener("DOMContentLoaded", function () { - - if (document.getElementById("expression-language")) { - const expressions = [ - { - name: "Date information", - editor: [ - { expression: "${date}", description: "the date corresponding to the moment where the request passed. The field is in Date Time format, with default format *yyy-mm-ddTHH:MM:SS.sss*" }, - { expression: "${date.format('')}", description: "same field that the previous but with a chosen format." } - ], - values: [ - { expression: "${date}", description: "2021-11-25T10:53:25.366+01:00" }, - { expression: "${date.format('yyy-MM-dd')}", description: "2021-11-25" } - ] - }, - { - name: "Service information", - editor: [ - { expression: "${service.domain}", description: "matched service domain by the query" }, - { expression: "${service.subdomain}", description: "matched service subdomain by the query" }, - { expression: "${service.tld}", description: "matched top level domain by the query" }, - { expression: "${service.env}", description: "Otoroshi environment of the matched service" }, - { expression: "${service.id}", description: "matched service id" }, - { expression: "${service.name}", description: "matched service name" }, - { expression: "${service.groups[:]}", description: "get nth group of the service or returned the default value" }, - { expression: "${service.groups[]}", description: "get nth group of the service or returned `no-group-` as value" }, - { expression: "${service.metadata.:}", description: "get the metadata of the service or returned the default value" }, - { expression: "${service.metadata.}", description: "get the metadata of the service or returned `no-meta-` as value" }, - ], - values: [ - { expression: "${service.domain}", description: "myservice.oto.tools" }, - { expression: "${service.subdomain}", description: "myservice" }, - { expression: "${service.tld}", description: "oto.tools" }, - { expression: "${service.env}", description: "prod" }, - { expression: "${service.id}", description: "GnzxRRWi..." }, - { expression: "${service.name}", description: "service" }, - { expression: "${service.groups[0:'unkown group']}", description: "unknown-group" }, - { expression: "${service.groups[0]}", description: "default-group" }, - { expression: "${service.metadata.test:'default-value'}", description: "default-value" }, - { expression: "${service.metadata.foo}", description: "bar" }, - ] - }, - { - name: "Request information", - editor: [ - { expression: "${req.fullUrl}", description: "the complete URL with protocol, host and relative URI" }, - { expression: "${req.path}", description: "the path of the request" }, - { expression: "${req.uri}", description: "the relative URI" }, - { expression: "${req.host}", description: "the host of the request" }, - { expression: "${req.domain}", description: "the domain of the request" }, - { expression: "${req.method}", description: "the method of the request" }, - { expression: "${req.protocol}", description: "the protocol of the request" }, - { expression: "${req.headers.
:''}", description: "get specific header of the request" }, - { expression: "${req.headers.
}", description: "get specific header of the request or get `no-header-
` as value" }, - { expression: "${req.query.:''}", description: "get specific query param of the request" }, - { expression: "${req.query.}", description: "get specific query param of the request or get `no-path-param-` as value" }, - { expression: "${req.pathparams.:''}", description: "get specific path param of the request" }, - { expression: "${req.pathparams.}", description: "get specific path param of the request or get `no-path-param-` as value" }, - ], - values: [ - { expression: "${req.fullUrl}", description: "http://api.oto.tools:8080/api/?foo=bar" }, - { expression: "${req.path}", description: "/api/" }, - { expression: "${req.uri}", description: "/api/?foo=bar" }, - { expression: "${req.host}", description: "api.oto.tools:8080" }, - { expression: "${req.domain}", description: "api.oto.tools" }, - { expression: "${req.method}", description: "GET" }, - { expression: "${req.protocol}", description: "http" }, - { expression: "${req.headers.foob:default value>", description: "default value" }, - { expression: "${req.headers.foo}", description: "bar" }, - { expression: "${req.query.foob:default value}", description: "default value" }, - { expression: "${req.query.foo}", description: "bar" }, - { expression: "${req.pathparams.foob:'default value'}", description: "default value" }, - { expression: "${req.pathparams.foo}", description: "bar" }, - ] - }, - { - name: "Apikey information", - editor: [ - { expression: "${apikey.name}", description: "if apikey is present, the client name of the apikey" }, - { expression: "${apikey.id}", description: "if apikey is present in the request, the client id of the apikey" }, - { expression: "${apikey.metadata.:''}", description: "if apikey is present, got the expected metadata, else got the default value" }, - { expression: "${apikey.metadata.}", description: "if apikey is present, got the expected metadata, else got the default value `no-meta-`" }, - { expression: "${apikey.tags[:'']}", description: "if apikey is present, got the nth tags or the default value" }, - { expression: "${apikey.tags[]}", description: "if apikey is present, got the nth tags or `no-tag-` as value" }, - ], - values: [ - { expression: "${apikey.name}", description: "Otoroshi Backoffice ApiKey" }, - { expression: "${apikey.id}", description: "admin-api-apikey-id" }, - { expression: "${apikey.metadata.myfield:'default value'}", description: "default value" }, - { expression: "${apikey.metadata.foo}", description: "bar" }, - { expression: "${apikey.tags['0':'no-found-tag']}", description: "no-found-tag" }, - { expression: "${apikey.tags['0']}", description: "one-tag" }, - ] - }, - { - name: "Token information", - context: "Only on jwt verifier fields", - editor: [ - { expression: "${token..replace('','')}", description: "get token field and replace a value by b or get `no-token-` as value" }, - { expression: "${token..replaceAll('','')}", description: "get token field and replace **all** a value by b or get `no-token-` as value" }, - { expression: "${token.|token.:}", description: "get claim of the token, ot the second claim of the token or a default value if not present" }, - { expression: "${token.|token.}", description: "get claim of the token or `no-token-$field-$field2` if not present" }, - { expression: "${token.:}", description: "get claim of the token or a default value if not present" }, - { expression: "${token.}", description: "get claim of the token" }, - ], - values: [ - { expression: "${token.foo.replace('o','a')}", description: "fao" }, - { expression: "${token.foo.replaceAll('o','a')}", description: "faa" }, - { expression: "${token.foob|token.foob2:'not-found'}", description: "not-found" }, - { expression: "${token.foob|token.foo}", description: "foo" }, - { expression: "${token.foob:'not-found-foob'}", description: "not-found-foob" }, - { expression: "${token.foo}", description: "bar" }, - ] - }, - { - name: "System Environment information", - editor: [ - { expression: "${env.:}", description: "get system environment variable or a default value if not present" }, - { expression: "${env.}", description: "get system environment variable or `no-env-var-` if not present" }, - ], - values: [ - { expression: "${env.java_h:'not-found-java_h'}", description: "not-found-java_h" }, - { expression: "${env.PATH}", description: "/usr/local/bin:" }, - ] - }, - { - name: "Environment information", - editor: [ - { expression: "${config.:}", description: "get environment variable or a default value if not present" }, - { expression: "${config.}", description: "get environment variable or `no-config-` if not present" }, - ], - values: [ - { expression: "${config.http.ports:'not-found'}", description: "not-found" }, - { expression: "${config.http.port}", description: "8080" }, - ] - }, - { - name: "Context information", - editor: [ - { expression: "${ctx..replace('','')}", description: "get field and replace a value by b in the string, or set `no-ctx-` as value" }, - { expression: "${ctx..replaceAll('','')}", description: "get field and replace all a value by b in the string, or set `no-ctx-` as value" }, - { expression: "${ctx.|ctx.:}", description: "get field or if empty the second field, or the set the default value" }, - { expression: "${ctx.|ctx.}", description: "get field or if empty the second field, or the set `no-ctx--` as value" }, - { expression: "${ctx.:}", description: "get field or the set the default value" }, - { expression: "${ctx.}", description: "get field or the set `no-ctx-` as value" }, - { expression: "${ctx.useragent.}", description: "get user agent field or set `no-ctx-` as value" }, - { expression: "${ctx.geolocation.}", description: "get geolocation field or set `no-ctx-` as value" }, - ], - values: [ - { expression: "${ctx.foo.replace('o','a')}", description: "fao" }, - { expression: "${ctx.foo.replaceAll('o','a')}", description: "faa" }, - { expression: "${ctx.foob|ctx.foot:'not-found'}", description: "not-found" }, - { expression: "${ctx.foob|ctx.foo}", description: "bar" }, - { expression: "${ctx.foob:'other'}", description: "other" }, - { expression: "${ctx.foo}", description: "bar" }, - { expression: "${ctx.useragent.foo}", description: "no-ctx-foo" }, - { expression: "${ctx.geolocation.foo}", description: "no-ctx-foo" }, - ] - }, - { - name: "User information", - context: "If call to a private app", - editor: [ - { expression: "${user.name}", description: "get user name" }, - { expression: "${user.email}", description: "get user email" }, - { expression: "${user.metadata.:}", description: "get metadata of user or get the default value" }, - { expression: "${user.metadata.}", description: "get metadata of user or `no-meta-` as value" }, - { expression: "${user.profile.:}", description: "get field of profile of user or get the default value" }, - { expression: "${user.profile.}", description: " get field of profile of user or `no-profile-` as value" }, - ], - values: [ - { expression: "${user.name}", description: "Otoroshi Admin" }, - { expression: "${user.email}", description: "admin@otoroshi.io" }, - { expression: "${user.metadata.username:'not-found'}", description: "not-found" }, - { expression: "${user.metadata.username}", description: "no-meta-username" }, - { expression: "${user.profile.username:'not-found'}", description: "not-found" }, - { expression: "${user.profile.name}", description: "Otoroshi Admin" }, - ], - } - ] - - const container = document.createElement("div"); - - function createBloc(item, i) { - const container = document.createElement("div"); - - const h2 = document.createElement("h2"); - h2.textContent = item.name; - container.appendChild(h2); - - if (item.context) { - const span = document.createElement("span"); - span.textContent = item.context; - span.style.fontStyle = "italic"; - container.appendChild(span); - } - - const editor = document.createElement("div"); - editor.classList.add("editor"); - - const editorContent = document.createElement("div"); - - item.editor.forEach(({ expression, description }) => { - const p = document.createElement("p"); - - const code = document.createElement("code"); - code.textContent = expression; - - const span = document.createElement("span"); - span.textContent = description; - - p.appendChild(code); - p.appendChild(span); - - editorContent.appendChild(p); - }) - - const valuesContent = document.createElement("div"); - - valuesContent.appendChild(Example(item.name)); - - item.values.forEach(({ expression, description }) => { - const p = document.createElement("p"); - - const code = document.createElement("code"); - code.textContent = expression; - - const span = document.createElement("span"); - span.classList.add("editor-value") - span.textContent = description; - - p.appendChild(code); - p.appendChild(span); - - valuesContent.appendChild(p); - }); - - editor.appendChild(editorContent); - editor.appendChild(valuesContent); - - - container.appendChild(editor); - return container - } - - function Example(name) { - const div = document.createElement("div"); - div.classList.add("editor-title"); - - const span = document.createElement("span"); - span.textContent = name; - - div.appendChild(span); - return div; - } - - expressions.forEach(item => { - container.appendChild(createBloc(item)); - }) - - document.getElementById("expressions").appendChild(container); - - container.style.background = "linear-gradient(to right, #eee 60%, #303740 40%)" - container.style.padding = "12px" - } - - else if (document.getElementById("data-exporters")) { - const filtering = [ - { - name: "Keep events with", - editor: [ - { expression: '{ "": "" }', description: "a field key with value" }, - { expression: '{ "": { "$wildcard": "*" } }', description: "a field starting with value" }, - { expression: '{ "": { "": "" } }', description: "a sub-field with value" }, - { expression: '{ "": }', description: "a field with the specific value as number" }, - { expression: '{ "": { "$gt": } }', description: "a field with number value greater than number" }, - { expression: '{ "": { "$gte": } }', description: "a field with number value greater or equal to number" }, - { expression: '{ "": { "$lt": } }', description: "a field with number value lower than number" }, - { expression: '{ "": { "$lte": } }', description: "a field with number value lower or equal to number" }, - { expression: '{ "": { "$between": { "min": , "max": } } }', description: "a field with value between two values" }, - { expression: '{ "": { "$and": [ { "": "" }, { "" : "" }] } }', description: "an object with two fields with values" }, - { expression: '{ "": { "$or": [ { "": "" }, { "" : "" }] } }', description: "an object with one subfield matching an element of the list" }, - { expression: '{ "": ["", ""] }', description: "an array field with values" }, - { expression: '{ "": { "contains": "" } }', description: "an array field containing a specific value" }, - { expression: '{ "": { "$all": ["", ""] } }', description: "and array field containing all specific values" } - ], - values: [ - { expression: '{ "foo": "bar" }', description: "Keep events with foo as key and bar as value" }, - { expression: '{ "type": { "$wildcard": "Alert*" } }', description: "Keep events with type field starting with Alert" }, - { expression: '{ "inner": { "foo": "bar" } }', description: "Keep events with sub field foo at value bar" }, - { expression: '{ "status": 200 }', description: "Keep events with status code at 200 (as number check)" }, - { expression: '{ "status": { "$gt": 100 } }', description: "Keep events with status code greater than 100" }, - { expression: '{ "status": { "$gte": 100 } }', description: "Keep events with status code greater or equal to 100" }, - { expression: '{ "status": { "$lt": 100 } }', description: "Keep events with status code lower than 100" }, - { expression: '{ "status": { "$lte": 100 } }', description: "Keep events with status code lower or equal to 100" }, - { expression: '{ "status": { "$between": { "min": 100, "max": 200 } } }', description: "Keep events with status code between 100 and 200" }, - { expression: '{ "inner": { "$and": [ { "foo": "bar" }, { "bar" : "foo" }] } }', description: "Keep events matching the list of key-value" }, - { expression: '{ "inner": { "$or": [ { "foo": "bar" }, { "bar" : "foo" }] } }', description: "Keep events matching one condition of the list of key-value" }, - { expression: '{ "codes": ["a", "b"] }', description: "Keep events with an array codes which strictly containing values a and b" }, - { expression: '{ "codes": { "contains": "a" } }', description: "Keep events with an array codes containing an a value" }, - { expression: '{ "codes": { "$all": ["a", "b"] } }', description: "Keep events with an array codes containing at minima a and b values" } - ] - } - ] - - const container = document.createElement("div"); - - function createBloc(item, i) { - const container = document.createElement("div"); - - const h2 = document.createElement("h2"); - h2.textContent = item.name; - container.appendChild(h2); - - if (item.context) { - const span = document.createElement("span"); - span.textContent = item.context; - span.style.fontStyle = "italic"; - container.appendChild(span); - } - - const editor = document.createElement("div"); - editor.classList.add("editor"); - - const editorContent = document.createElement("div"); - - item.editor.forEach(({ expression, description }) => { - const p = document.createElement("p"); - - const code = document.createElement("code"); - code.textContent = expression; - - const span = document.createElement("span"); - span.textContent = description; - - p.appendChild(code); - p.appendChild(span); - - editorContent.appendChild(p); - }) - - const valuesContent = document.createElement("div"); - - valuesContent.appendChild(Example(item.name)); - - item.values.forEach(({ expression, description }) => { - const p = document.createElement("p"); - - const code = document.createElement("code"); - code.textContent = expression; - - const span = document.createElement("span"); - span.classList.add("editor-value") - span.textContent = description; - - p.appendChild(code); - p.appendChild(span); - - valuesContent.appendChild(p); - }); - - editor.appendChild(editorContent); - editor.appendChild(valuesContent); - - - container.appendChild(editor); - return container - } - - function Example(name) { - const div = document.createElement("div"); - div.classList.add("editor-title"); - - const span = document.createElement("span"); - span.textContent = name; - - div.appendChild(span); - return div; - } - - filtering.forEach(item => { - container.appendChild(createBloc(item)); - }) - - document.getElementById("filtering").appendChild(container); - - container.style.background = "linear-gradient(to right, #eee 60%, #303740 40%)" - container.style.padding = "12px" - } -}); \ No newline at end of file diff --git a/docs/manual/js/groups.js b/docs/manual/js/groups.js deleted file mode 100644 index e9ec53c349..0000000000 --- a/docs/manual/js/groups.js +++ /dev/null @@ -1,167 +0,0 @@ -groupChangeListeners = []; - -window.groupChanged = function(callback) { - groupChangeListeners.push(callback); -} - -$(function() { - - // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. - // The catalog of groups can be defined in the sbt parameters to initialize the group. - - var groupCookie = "paradoxGroups"; - var cookieTg = getCookie(groupCookie); - var currentGroups = {}; - - var catalog = {} - var supergroupByGroup = {}; - - if(cookieTg != "") - currentGroups = JSON.parse(cookieTg); - - // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie - function setCookie(cookieName, cookieValue, daysToExpire) { - if (!daysToExpire) daysToExpire = 365; - const now = new Date(); - now.setDate(now.getDate() + daysToExpire); - // The lax value will send the cookie for all same-site - // requests and top-level navigation GET requests. This - // is sufficient for user tracking, but it will prevent - // many CSRF attacks. This is the default value in modern browsers. - document.cookie = `${cookieName}=${encodeURIComponent(cookieValue)};expires=${now.toUTCString()};path=/;samesite=lax`; - } - - // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_2_Get_a_sample_cookie_named_test2 - function getCookie(cookieName) { - const cookieAttr = decodeURIComponent(document.cookie) - .split(";") - .find(row => row.trimStart().startsWith(cookieName)) - return cookieAttr ? cookieAttr.split("=")[1] : ""; - } - - $("dl").has("dd > pre").each(function() { - var dl = $(this); - dl.addClass("tabbed"); - var dts = dl.find("dt"); - dts.each(function(i) { - var dt = $(this); - dt.html("" + dt.text() + ""); - }); - var dds = dl.find("dd"); - dds.each(function(i) { - var dd = $(this); - dd.hide(); - if (dd.find("blockquote").length) { - dd.addClass("has-note"); - } - }); - - // Default to the first tab, for grouped tabs switch again later - switchToTab(dts.first()); - - dts.first().addClass("first"); - dts.last().addClass("last"); - }); - - // Determine all supergroups, populate 'catalog' and 'supergroupByGroup' accordingly. - $(".supergroup").each(function() { - var supergroup = $(this).attr('name').toLowerCase(); - var groups = $(this).find(".group"); - - catalog[supergroup] = []; - - groups.each(function() { - var group = "group-" + $(this).text().toLowerCase(); - catalog[supergroup].push(group); - supergroupByGroup[group] = supergroup; - }); - - $(this).on("change", function() { - switchToGroup(supergroup, this.value); - }); - }); - - // Switch to the right initial groups - for (var supergroup in catalog) { - var current = queryParamGroup(supergroup) || currentGroups[supergroup] || catalog[supergroup][0]; - - switchToGroup(supergroup, current); - } - - $("dl.tabbed dt a").click(function(e){ - e.preventDefault(); - var currentDt = $(this).parent("dt"); - var currentDl = currentDt.parent("dl"); - - var currentGroup = groupOf(currentDt); - - var supergroup = supergroupByGroup[currentGroup] - if (supergroup) { - switchToGroup(supergroup, currentGroup); - } else { - switchToTab(currentDt); - } - }); - - function queryParamGroup(supergroup) { - var value = new URLSearchParams(window.location.search).get(supergroup) - if (value) { - return "group-" + value.toLowerCase(); - } else { - return ""; - } - } - - function switchToGroup(supergroup, group) { - currentGroups[supergroup] = group; - setCookie(groupCookie, JSON.stringify(currentGroups)); - - // Dropdown switcher: - $("select") - .has("option[value=" + group +"]") - .val(group); - - // Inline snippets: - catalog[supergroup].forEach(peer => { - if (peer === group) { - $("." + group).show(); - } else { - $("." + peer).hide(); - } - }) - - // Tabbed snippets: - $("dl.tabbed").each(function() { - var dl = $(this); - dl.find("dt").each(function() { - var dt = $(this); - if(groupOf(dt) == group) { - switchToTab(dt); - } - }); - }); - - groupChangeListeners.forEach(listener => listener(group, supergroup, catalog)); - } - - function switchToTab(dt) { - var dl = dt.parent("dl"); - dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - dt.addClass("current"); - var currentContent = dt.next("dd").addClass("current").show(); - dl.css("height", dt.height() + currentContent.height()); - } - - function groupOf(elem) { - const classAttribute = elem.next("dd").find("pre").attr("class"); - if (classAttribute) { - const currentClasses = classAttribute.split(' '); - const regex = new RegExp("^group-.*"); - const matchingClass = currentClasses.find(cc => regex.test(cc)); - if (matchingClass) return matchingClass; - } - - // No class found? Then use the tab title - return "group-" + elem.find('a').text().toLowerCase(); - } -}); diff --git a/docs/manual/js/magellan.js b/docs/manual/js/magellan.js deleted file mode 100644 index 52d231ecfb..0000000000 --- a/docs/manual/js/magellan.js +++ /dev/null @@ -1,25 +0,0 @@ -$(function() { - - // add magellan targets to anchor headers, up to depth 3 - $("a.anchor").each(function() { - var anchor = $(this); - var name = anchor.attr("name"); - var header = anchor.parent(); - if (header.is("h1") || header.is("h2") || header.is("h3")) { - header.attr("id", name).attr("data-magellan-target", name); - } - }); - - // enable magellan plugin on the page navigation - $(".page-nav").each(function() { - var nav = $(this); - - // strip page navigation links down to just the hash fragment - nav.find("a").attr('href', function(_, current){ - return this.hash ? this.hash : current; - }); - - new Foundation.Magellan(nav); - }); - -}); diff --git a/docs/manual/js/ngplugins.js b/docs/manual/js/ngplugins.js deleted file mode 100644 index c1630e26ee..0000000000 --- a/docs/manual/js/ngplugins.js +++ /dev/null @@ -1,29 +0,0 @@ -document.addEventListener("DOMContentLoaded", function() { - const plugins = [...document.getElementsByClassName("ng-plugin")]; - plugins.forEach((plugin, i) => { - const fullContent = [...plugin.children]; - const title = fullContent[0]; - const description = fullContent[7]; - const smallContent = [ title, description ]; - title.children[0].setAttribute('href', '#' + plugin.id); - plugin.replaceChildren(...smallContent) - plugin.classList.remove("plugin-hidden"); - plugin.addEventListener("click", e => { - if (plugin.classList.contains("plugin-open")) { - plugin.replaceChildren(...smallContent); - plugin.classList.remove("plugin-open"); - } else { - plugin.replaceChildren(...fullContent); - plugin.classList.add("plugin-open"); - } - }); - }); - if (plugins.length > 0 && window.location.hash && window.location.hash.length > 1) { - const plugin = window.location.hash.substring(1); - setTimeout(function() { - const elem = document.getElementById(plugin) - elem.click(); - elem.scrollIntoView(); - }, 300) - } -}); \ No newline at end of file diff --git a/docs/manual/js/page.js b/docs/manual/js/page.js deleted file mode 100644 index a847efdc07..0000000000 --- a/docs/manual/js/page.js +++ /dev/null @@ -1,172 +0,0 @@ -$(function () { - $('.swagger-frame').each(function () { - - var url = window.location.pathname.indexOf('devmanual') > -1 ? 'https://maif.github.io/otoroshi/swagger-ui/index-dev.html' : 'https://maif.github.io/otoroshi/swagger-ui/index.html'; - - $(this).append('