diff --git a/docs/manual/about.html b/docs/manual/about.html new file mode 100644 index 0000000000..4c7b506efd --- /dev/null +++ b/docs/manual/about.html @@ -0,0 +1,455 @@ + + + + +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 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 new file mode 100644 index 0000000000..528bfc2fb9 --- /dev/null +++ b/docs/manual/api.html @@ -0,0 +1,456 @@ + + + + +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.

+

Otoroshi also provides some connectors that uses the Otoroshi admin API to automate Otorshi’s instances when used with stuff like containers orchestrators. For more informations about that, just go to the third party integrations chapter

+

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/archi.html b/docs/manual/archi.html new file mode 100644 index 0000000000..38d47af151 --- /dev/null +++ b/docs/manual/archi.html @@ -0,0 +1,434 @@ + + + + +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 new file mode 100644 index 0000000000..d23061f1ad --- /dev/null +++ b/docs/manual/code/openapi.json @@ -0,0 +1,19464 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Otoroshi Admin API", + "description" : "Admin API of the Otoroshi reverse proxy", + "version" : "1.5.0-rc.2", + "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" : "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/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/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/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/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/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/{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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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.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.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.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.models.TeamId" : { + "type" : "string", + "description" : "team id" + }, + "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" + } + } + }, + "ErrorTemplateList" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/otoroshi.models.ErrorTemplate" + } + }, + "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.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.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" + } + } + }, + "TokenResponse" : { + "type" : "object", + "description" : "User login token response", + "properties" : { + "valid" : { + "type" : "string" + } + } + }, + "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" + } + } + }, + "LetsEncryptCertBody" : { + "type" : "object", + "description" : "PEM encoded certificate" + }, + "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.models.AlwaysMatch" : { + "type" : "object", + "description" : "Always select target", + "properties" : { + "type" : { + "type" : "string", + "enum" : [ "Always" ] + } + } + }, + "otoroshi.models.TenantId" : { + "type" : "string", + "description" : "organization id" + }, + "otoroshi.auth.SAMLCanocalizationMethod" : { + "description" : "Canonicalization Method for XML Signatures", + "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 for a file data exporter", + "type" : "object", + "properties" : { + "path" : { + "description" : "File path", + "type" : "string" + }, + "maxFileSize" : { + "format" : "int32", + "description" : "Max file size in bytes", + "type" : "integer" + }, + "type" : { + "description" : "the kind of exporter", + "type" : "string", + "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] + } + } + }, + "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.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" + }, + "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" + }, + "_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.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.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.models.SecComVersion" : { + "type" : "string", + "enum" : [ "V1", "v2" ], + "description" : "Version of the challenge token" + }, + "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.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.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.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" + }, + "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" + }, + "_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.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" : "Data exporter that will log everything to the 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.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.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" + } + } + }, + "UpdateQuotasBody" : { + "type" : "string", + "description" : "" + }, + "otoroshi.models.DataExporterConfigFiltering" : { + "description" : "Settings to match otoroshi events", + "type" : "object", + "properties" : { + "include" : { + "type" : "array", + "items" : { + "type" : "object" + }, + "description" : "Exclude the events matching one of those filters" + }, + "exclude" : { + "type" : "array", + "items" : { + "type" : "object" + }, + "description" : "Include the events matching one of those filters" + } + } + }, + "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.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.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.models.DataExporterConfigType" : { + "type" : "string", + "enum" : [ "kafka", "pulsar", "elastic", "webhook", "file", "mailer", "custom", "none", "console", "metrics" ], + "description" : "Type of data exporter" + }, + "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.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.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.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" ] + } + } + }, + "AuditEventList" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/otoroshi.events.AuditEvent" + } + }, + "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 downstream 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.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.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.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.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.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.auth.SAMLSignatureAlgorithm" : { + "description" : "Algorithm to sign SAML requests", + "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" + }, + "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" + } + } + }, + "StringList" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "otoroshi.models.ExporterRef" : { + "description" : "Reference to a data exporter", + "type" : "object", + "properties" : { + "ref" : { + "description" : "Script id", + "type" : "string" + }, + "type" : { + "description" : "the kind of exporter", + "type" : "string", + "enum" : [ "elastic", "webhook", "kafka", "pulsar", "file", "mailer", "custom", "console", "metrics" ] + }, + "config" : { + "description" : "Script 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" + } + } + }, + "HealthCheckEventList" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/otoroshi.events.HealthCheckEvent" + } + }, + "otoroshi.models.OutageStrategy" : { + "type" : "string", + "enum" : [ "AllServicesPerGroup", "OneServicePerGroup" ] + }, + "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" + } + } + }, + "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" + } + } + }, + "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.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.events.KafkaConfig" : { + "description" : "Settings for connection to a kafka cluster", + "type" : "object", + "properties" : { + "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.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.models.IndexSettingsInterval" : { + "description" : "Elasticseach indexation interval", + "type" : "object", + "properties" : { } + }, + "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.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.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" + } + } + }, + "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.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.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.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.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" + } + } + }, + "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.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" + } + } + }, + "HostMetrics" : { + "type" : "object", + "description" : "Host metrics" + }, + "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.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.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.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" + } + } + }, + "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.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.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" + }, + "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" + } + } + }, + "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.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.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.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.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.auth.BasicAuthModuleConfig" : { + "description" : "Authentication module that let you use otoroshi as the identity provider", + "type" : "object", + "properties" : { + "sessionMaxAge" : { + "format" : "int32", + "description" : "max age for the session cookie in seconds", + "type" : "integer" + }, + "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" + }, + "name" : { + "description" : "name of the module", + "type" : "string" + }, + "webauthn" : { + "description" : "Use webauthn for login", + "type" : "boolean" + }, + "id" : { + "description" : "id of the module", + "type" : "string" + }, + "type" : { + "description" : "the type of the module", + "type" : "string", + "enum" : [ "saml", "oauth1", "oauth2", "ldap", "basic" ] + }, + "_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" + }, + "desc" : { + "description" : "description of the module", + "type" : "string" + }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + }, + "description" : "Entity tags" + } + } + }, + "otoroshi.utils.mailer.EmailLocation" : { + "description" : "Email location settings", + "type" : "object", + "properties" : { + "name" : { + "description" : "Destination name", + "type" : "string" + }, + "email" : { + "description" : "Email address", + "type" : "string" + } + } + }, + "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.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.models.NoneGeolocationSettings" : { + "type" : "object", + "description" : "No geolocation extraction", + "properties" : { + "type" : { + "type" : "string", + "enum" : [ "none" ] + } + } + }, + "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.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.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.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.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.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.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" ] + } + } + }, + "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" + }, + "PemCertificateBody" : { + "type" : "string", + "description" : "PEM encoded certificate" + }, + "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" + } + } + }, + "OutagesList" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/otoroshi.models.Outage" + } + }, + "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.models.DataExporterConfig" : { + "description" : "Module to export otoroshi specific events to whatever destination you want", + "type" : "object", + "properties" : { + "desc" : { + "description" : "Description", + "type" : "string" + }, + "_loc" : { + "description" : "location", + "$ref" : "#/components/schemas/otoroshi.models.EntityLocation" + }, + "bufferSize" : { + "format" : "int32", + "description" : "buffer size", + "type" : "integer" + }, + "jsonWorkers" : { + "format" : "int32", + "description" : "nb workers", + "type" : "integer" + }, + "groupDuration" : { + "description" : "duration", + "type" : "number" + }, + "groupSize" : { + "format" : "int32", + "description" : "Group size", + "type" : "integer" + }, + "type" : { + "description" : "Type of data exporter", + "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfigType" + }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + }, + "description" : "Entity tags" + }, + "sendWorkers" : { + "format" : "int32", + "description" : "send workers", + "type" : "integer" + }, + "id" : { + "description" : "Id", + "type" : "string" + }, + "name" : { + "description" : "Name", + "type" : "string" + }, + "metadata" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + }, + "description" : "Metadata" + }, + "config" : { + "description" : "Data Exporter config", + "$ref" : "#/components/schemas/otoroshi.models.Exporter" + }, + "projection" : { + "description" : "projection", + "type" : "object" + }, + "enabled" : { + "description" : "Boolean", + "type" : "boolean" + }, + "filtering" : { + "description" : "filtering", + "$ref" : "#/components/schemas/otoroshi.models.DataExporterConfigFiltering" + } + } + }, + "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" + }, + "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.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 for metrics labels", + "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" : "Exposed labels" + } + } + }, + "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.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.events.PulsarConfig" : { + "description" : "Settings for connection to a pulsar cluster", + "type" : "object", + "properties" : { + "mtlsConfig" : { + "description" : "TLS config to access the cluster", + "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" + }, + "tlsTrustCertsFilePath" : { + "oneOf" : [ { + "$ref" : "#/components/schemas/Null" + }, { + "type" : "string" + } ], + "description" : "Trusted cert 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 cluster url", + "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" ] + }, + "_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" + }, + "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.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.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.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" + }, + "mtlsConfig" : { + "description" : "TLS settings for http client", + "$ref" : "#/components/schemas/otoroshi.utils.http.MtlsConfig" + }, + "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" + } + } + }, + "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.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.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.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.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" + }, + "_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" + }, + "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.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.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.events.AuditEvent" : { + "type" : "object", + "description" : "Audit trail event" + }, + "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.models.SecComInfoTokenVersion" : { + "type" : "string", + "enum" : [ "Legacy", "Latest" ], + "description" : "Version of the info token" + }, + "BulkPatchBody" : { + "type" : "array", + "description" : "Body composed of stringified JSON-Patch lines, each one representing updates to an entity", + "items" : { + "$ref" : "#/components/schemas/PatchDocument" + } + }, + "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.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" + } + } + }, + "Null" : { + "type" : "object", + "description" : "no value object, used to represent a None option value" + }, + "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.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" + } + } + }, + "PatchBody" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/PatchDocument" + } + }, + "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.models.UserAgentSettings" : { + "description" : "Settings to extract informations about user agent (for otoroshi events)", + "type" : "object", + "properties" : { + "enabled" : { + "description" : "User agent extraction enabled", + "type" : "boolean" + } + } + } + }, + "securitySchemes" : { + "otoroshi_auth" : { + "type" : "http", + "scheme" : "basic" + } + } + } +} diff --git a/docs/manual/code/swagger.json b/docs/manual/code/swagger.json new file mode 100644 index 0000000000..457835c92d --- /dev/null +++ b/docs/manual/code/swagger.json @@ -0,0 +1,8099 @@ +{ + "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 new file mode 100644 index 0000000000..07be6c3544 --- /dev/null +++ b/docs/manual/content-pretty.json @@ -0,0 +1,765 @@ +[ + { + "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 MAIF. Naturally we turned to PaaS solutions and chose the excellent Clever-Cloud 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 Service Mesh Pattern but the deployement model of Clever-Cloud 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 Clever-Cloud 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 MAIF like Izanami 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\nOtoroshi also provides some connectors that uses the Otoroshi admin API to automate Otorshi's instances when used with stuff like containers orchestrators. For more informations about that, just go to the @ref:[third party integrations chapter](./integrations/index.md)\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": "archi.md", + "id": "/archi.md", + "url": "/archi.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 [React](https://reactjs.org/) 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-beanstalk.md", + "id": "/deploy/aws-beanstalk.md", + "url": "/deploy/aws-beanstalk.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](../getotoroshi/fromdocker.md) 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](../firstrun/run.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](../getotoroshi/fromdocker.md), build a zip, and do all the Otoroshi custom configuration using ENVs.\n\nOr you download the @ref:[otoroshi.jar](../getotoroshi/frombinaries.md), 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:8\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 downstream 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 `app.storage=redis`, `app.redis.host` and `app.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": "clevercloud.md", + "id": "/deploy/clevercloud.md", + "url": "/deploy/clevercloud.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](../firstrun/env.md), 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": "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\n@@@ index\n\n* [Kubernetes](./kubernetes.md)\n* [Clever Cloud](./clevercloud.md)\n* [AWS - Elastic Beanstalk](./aws-beanstalk.md)\n* [others](./other.md) \n* [Scaling](./scaling.md) \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.0-rc.2\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.0-rc.2-jdk11\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": "other.md", + "id": "/deploy/other.md", + "url": "/deploy/other.html", + "title": "Others", + "content": "# Others\n\nOtoroshi can run wherever you want, even on a raspberry pi (Cluster^^) ;)\n\nThis section is not finished yet. So, as Otoroshi is available as a @ref:[Docker image](../getotoroshi/fromdocker.md) that you can run on any Docker compatible cloud, just go ahead and use it on cloud provider until we have more detailed documentation.\n\n## Running Otoroshi on AWS Elastic Beanstalk\n\nSee the @ref:[dedicated page to run Otoroshi on AWS Elastic Beanstalk](./aws-beanstalk.md)\n\n## Running Otoroshi on Amazon Elastic Container Service\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n\n## Running Otoroshi on GCE\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Google Compute Engine container integration](https://cloud.google.com/compute/docs/containers/deploying-containers)\n\n## Running Otoroshi on Azure\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Azure Container Service](https://azure.microsoft.com/en-us/services/container-service/)\n\n## Running Otoroshi on Heroku\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Docker integration](https://devcenter.heroku.com/articles/container-registry-and-runtime)\n\n## Running Otoroshi on CloudFoundry\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Docker integration](https://docs.cloudfoundry.org/adminguide/docker.html)\n\n## Running Otoroshi on your own infrastructure\n\nAs Otoroshi is a [Play Framework](https://www.playframework.com) application, you can read the doc about putting a `Play` app in production.\n\nhttps://www.playframework.com/documentation/2.6.x/ProductionConfiguration\n\nDownload the latest @ref:[Otoroshi distribution](../getotoroshi/frombinaries.md), unzip it, customize it and run it.\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](../topics/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 -Dapp.storage=file -Dapp.liveJs=true -Dhttps.port=9998 -D-Dapp.privateapps.port=9999 -Dapp.adminPassword=password -Dapp.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dapp.events.maxSize=0\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\n## Format the sources\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/fmt.sh\n```" + }, + { + "name": "features.md", + "id": "/features.md", + "url": "/features.html", + "title": "Features ", + "content": "# Features \n\n@@@ warning\nThis section is under construction\n@@@\n\nAll the features supported by **Otoroshi** are listed below\n\n* Dynamic changes at runtime without full reload \n* Can proxy any HTTP/HTTP2 server (websockets and streamed responses included)\n* Full featured admin Rest Api to control Otoroshi the way you want. Included, Swagger descriptor\n* Gorgeous React Web UI\n* Full end-to-end streaming of HTTP requests and responses\n* Completely non blocking and async internals\n* @ref:[Official Docker image](./getotoroshi/fromdocker.md)\n* @ref:[Multi backend datastore support](./firstrun/datastore.md)\n * Redis\n * In memory\n * Cassandra (experimental support)\n * filedb (not suitable for production usage)\t\n* Pluggable modules system (plugins) \n * you can create your own modules to change de behavior of Otoroshi per service or globally\n * impacts on access validation, routing, body transformation, apikey extraction\n * listen to internal otoroshi events\n * modules can be written and deployed from the UI\n * lot of module provided out of the box (see TODO:)\n* Full featured TLS integration\n * @ref:[Dynamic SSL termination](./topics/ssl.md)\n * mTLS support for input and output connections (end-to-end mTLS)\n * extended client certificate validation\n * TLS certificate automation (create, renew, etc) based on a CA certificate\n * ACME/Let's Encrypt support (create, renew)\n * on-the-fly certificate generation based on a CA certificate without request loss\n* Classic features for reverse proxying\n * expose the same service on multiple domain names (including wildcards)\n * support multiple loadbalancing algorithms\n * configurable circuit breaker per service, with timeouts per path and verb\n * @ref:[maintenance page per service](./usage/2-services.md)\n * @ref:[build page per service](./usage/2-services.md)\n * @ref:[force HTTPS usage per service](./usage/2-services.md)\n * @ref:[Add current Api key quotas usage in response headers](./usage/3-apikeys.md)\n * @ref:[Add current latencies in response headers](./usage/3-apikeys.md)\n * headers manipulation\n * routing headers\n * custom html error templates\n * healthcheck per service\n * sink services\n * CORS support\n * GZIP support\n * filtering on http verb and path\n* Api management features\n * throttling / daily quotas / monthly quotas per apikey\n * apikey authorization based on http verb and path\n * global throttling\n * global throttling per ip address\n * global or per service ip address blacklist / whitelist\n * automatic apikey secret rotation\n* Authentication modules\n * LDAP\n * In memory (managed by otoroshi)\n * OAuth2/OIDC\n * modules can be used for admin. backoffice login\n * webauthentication support\n * sessions management from UI\n* JWT token utilities\n * validate incoming JWT tokens\n * transform incoming JWT tokens\n * chain multiple validators\n* Analytics / Metrics\n * rich traffic events for each proxied http request\n * @ref:[Live metrics per service and globaly](./usage/4-monitor.md) \n * @ref:[Global metrics and analytics (requires elastic server)](./usage/7-metrics.md)\n * @ref:[Traffic events can be sent using webhooks or Kafka topic](./setup/dangerzone.md#analytics-settings)\n * multiple technical metrics exporters (statsd, datadog, prometheus)\n* Audit trail\n * @ref:[Global audit log alert log on admins actions](./usage/6-audit.md)\n * @ref:[Audit and alerts events can be sent using webhooks or Kafka topic](./setup/dangerzone.md#analytics-settings)\n * @ref:[Alerts events can be send to people by email using email provider (Mailgun, mailjet)](./integrations/mailgun.md)\n* Extract informations from `User-Agent` headers to enrich traffic events\n* Extract geolocation informations (need external service) to enrich traffic events\n* Support enterprise http proxies globaly and per service\n* TCP proxy with SNI and TLS passthrought support\n* TCP / UDP tunnelings\n * add web authentication on top of anything\n * local tunnel client with CLI or UI\n* @ref:[Canary mode per service](./topics/snow-monkey.md)\n* @ref:[Chaos engineering tools with the Snow Monkey](./topics/snow-monkey.md)\n* @ref:[Advanced CleverCloud integration (create services from CleverCloud apps)](./integrations/clevercloud.md) \n" + }, + { + "name": "configfile.md", + "id": "/firstrun/configfile.md", + "url": "/firstrun/configfile.html", + "title": "Config. with files", + "content": "# Config. with files\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## Common configuration\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.domain` | string | \"oto.tools\" | the domain on which Otoroshi UI/API is be exposed|\n| `app.rootScheme` | string | \"http\" | the scheme on which Otoroshi is exposed, either \"http\" or \"https\" |\n| `app.snowflake.seed` | number | 0 | this number will is used to generate unique ids across the cluster. Each Otorshi instance must have a unique seed. |\n| `app.events.maxSize` | number | 1000 | max number of analytic and alert events stored locally |\n| `app.backoffice.exposed` | boolean | true | does the current Otoroshi instance exposed a backoffice ui|\n| `app.backoffice.subdomain` | string | \"otoroshi\" | the subdomain on wich Otoroshi backoffice will be served |\n| `app.backoffice.session.exp` | number | 86400000 | the number of seconds before the Otoroshi backoffice session expires |\n| `app.privateapps.subdomain` | string | \"privateapps\" | the subdomain on which private apps UI are served |\n| `app.privateapps.session.exp` | number | 86400000 | the number of seconds before the private apps session expires |\n| `app.claim.sharedKey` | string | \"secret\" | the shared secret used for signing the JWT token passed between Otoroshi and backend services |\n| `app.webhooks.size` | number | 100 | number of events sent at most when calling one of the analytics webhooks |\n| `app.throttlingWindow` | number | 10 | time window (in seconds) used to compute throttling quotas for ApiKeys |\n\n## Admin API configuration\n\nWhen Otoroshi starts for the first time, its datastore is empty. As Otoroshi uses Otoroshi to expose its admin REST API, you'll have to provide the details for the admin API exposition. **This part is super important** because if you go to production with the default values, your Otoroshi server won't be secured anymore.\n\n@@@ warning\nYOU HAVE TO CUSTOMIZE THE FOLLOWING VALUES BEFORE GOING TO PRODUCTION !!\n@@@\n\nSome of the following terms will seem obscure to you, but you will learn their meaning in the following chapters :)\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.adminapi.exposed` | boolean | true | does the current Otoroshi instance expose an admin API |\n| `app.adminapi.targetSubdomain` | string | \"otoroshi-admin-internal-api\" | the subdomain on wich admin API call will be redirected from `app.adminapi.exposedSubdomain` |\n| `app.adminapi.exposedSubdomain` | string | \"otoroshi-api\" | the subdomain on wich the Otoroshi admin API will be exposed |\n| `app.adminapi.defaultValues.backOfficeGroupId` | string | \"admin-api-group\" | the name of the service groups that will contain the service descriptors for the Otoroshi admin API |\n| `app.adminapi.defaultValues.backOfficeApiKeyClientId` | string | \"admin-api-apikey-id\" | the client id of the Otoroshi admin API apikey |\n| `app.adminapi.defaultValues.backOfficeApiKeyClientSecret` | string | \"admin-api-apikey-secret\" | the client secret of the Otoroshi admin API apikey |\n| `app.adminapi.defaultValues.backOfficeServiceId` | string | \"admin-api-service\" | the id of the service descriptors for the Otoroshi admin API |\n| `app.adminapi.proxy.https` | boolean | false | whether or not the current Otoroshi instance serves its content over https. This setting is useful for the backoffice UI to access Otoroshi admin API |\n| `app.adminapi.proxy.local` | boolean | true | whether or not the admin API is accessible through `127.0.0.1`. This setting is useful for the backoffice UI to access Otoroshi admin API |\n\n## Secrets config\n\nWhen Otoroshi starts for the first time, its secrets are set by default. \n\n@@@ warning\nYOU HAVE TO CUSTOMIZE AT LEAST `otoroshi.secret` BEFORE GOING TO PRODUCTION !!\n@@@\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `otoroshi.secret` | string | 'verysecretvaluethatyoumustoverwrite' | default Otoroshi secret. This value is used by default for other secrets |\n| `otoroshi.sessions.secret` | string | `otoroshi.secret` | Secret used to cipher session ids |\n| `play.http.secret.key` | string | `otoroshi.secret` | the secret used to sign Otoroshi session cookie |\n\n## DB configuration\n\nAs Otoroshi supports multiple datastores, you'll have to provide some details about how to connect/configure it.\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.storage` | string | \"inmemory\" | what kind of storage engine you want to use. Possible values are `inmemory`, `file`, `redis`, `cassandra` |\n| `app.importFrom` | string | | a file path or a URL to an Otoroshi export file. If the datastore is empty on startup, this file will be used to import data to the empty DB |\n| `app.importFromHeaders` | array | [] | a list of `:` separated header to use if the `app.importFrom` setting is a URL |\n| `app.initialData` | object |  | object representing Otoroshi internal data as exported from danger zone so you don't need a config file and a data import file |\n| `app.redis.host` | string | \"localhost\" | the host of the redis server |\n| `app.redis.port` | number | 6379 | the port of the redis server |\n| `app.redis.slaves` | array | [] | the redis slaves lists |\n| `app.filedb.path` | string | \"./filefb\" | the path where filedb files will be written |\n| `app.cassandra.hosts` | string | \"127.0.0.1\" | the host of the cassandra server |\n| `app.cassandra.host` | string | \"127.0.0.1\" | the list of cassandra hosts |\n| `app.cassandra.port` | number | 9042 | the port of the cassandra servers |\n| `app.pg.uri` | string | | the uri of your pg database |\n| `app.pg.host` | string | localhost | the host of your pg database |\n| `app.pg.port` | number | 5432 | the port of your pg database |\n| `app.pg.database` | string | otoroshi | the database name |\n| `app.pg.user` | string | otoroshi | the username to connect to your pg database |\n| `app.pg.password` | string | otoroshi | the password to connect to your pg database |\n\n## Headers configuration\n\nOtoroshi uses a fair amount of http headers in order to work properly. The name of those headers are customizable to fit your needs.\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `otoroshi.headers.trace.label` | string | \"Otoroshi-Viz-From-Label\" | header to pass request tracing informations |\n| `otoroshi.headers.trace.from` | string | \"Otoroshi-Viz-From\" | header to pass request tracing informations (ip address) |\n| `otoroshi.headers.trace.parent` | string | \"Otoroshi-Parent-Request\" | header to pass request tracing informations (parent request id) |\n| `otoroshi.headers.request.adminprofile` | string | \"Otoroshi-Admin-Profile\" | header to pass admin name when the admin API is called from the Otoroshi backoffice |\n| `otoroshi.headers.request.clientid` | string | \"Otoroshi-Client-Id\" | header to pass apikey client id |\n| `otoroshi.headers.request.clientsecret` | string | \"Otoroshi-Client-Secret\" | header to pass apikey client secret |\n| `otoroshi.headers.request.id` | string | \"Otoroshi-Request-Id\" | header containing the id of the current request |\n| `otoroshi.headers.response.proxyhost` | string | \"Otoroshi-Proxied-Host\" | header containing the proxied host |\n| `otoroshi.headers.response.error` | string | \"Otoroshi-Error\" | header containing whether or not the request generated an error |\n| `otoroshi.headers.response.errormsg` | string | \"Otoroshi-Error-Msg\" | header containing error message if some |\n| `otoroshi.headers.response.proxylatency` | string | \"Otoroshi-Proxy-Latency\" | header containing the current latency induced by Otoroshi |\n| `otoroshi.headers.response.upstreamlatency` | string | \"Otoroshi-Upstream-Latency\" | header containing the current latency from Otoroshi to service backend |\n| `otoroshi.headers.response.dailyquota` | string | \"Otoroshi-Daily-Calls-Remaining\" | header containing the number of remaining daily call (apikey) |\n| `otoroshi.headers.response.monthlyquota` | string | \"Otoroshi-Monthly-Calls-Remaining\" | header containing the number of remaining monthly call (apikey) |\n| `otoroshi.headers.comm.state` | string | \"Otoroshi-State\" | header containing a random value for secured mode |\n| `otoroshi.headers.comm.stateresp` | string | \"Otoroshi-State-Resp\" | header containing a random value for secured mode |\n| `otoroshi.headers.comm.claim` | string | \"Otoroshi-Claim\" | header containing a JWT token for secured mode |\n| `otoroshi.headers.healthcheck.test` | string | \"Otoroshi-Health-Check-Logic-Test\" | header containing a logic test for healthcheck |\n| `otoroshi.headers.healthcheck.testresult` | string | \"Otoroshi-Health-Check-Logic-Test-Result\" | header containing the result of a logic test for healthcheck |\n| `otoroshi.headers.jwt.issuer` | string | \"Otoroshi\" | the name of the issuer for the JWT token |\n| `otoroshi.headers.canary.tracker` | string | \"Otoroshi-Canary-Id\" | header containing the ID of the canary session if enabled |\n\n## Play specific configuration\n\nAs Otoroshi is a [Play app](https://www.playframework.com/), you should take a look at [Play configuration documentation](https://www.playframework.com/documentation/2.6.x/Configuration) to tune its internal configuration\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `http.port` | number | 8080 | the http port used by Otoroshi. You can use 'disabled' as value if you don't want to use http |\n| `https.port` | number | disabled | the https port used by Otoroshi. You can use 'disabled' as value if you don't want to use https |\n| `http2.enabled` | boolean | false | whether or not http2 is enabled on the Otoroshi server. You need to configure https (listed bellow) to be able to use it |\n| `play.http.secret.key` | string | \"secret\" | the secret used to sign Otoroshi session cookie |\n| `play.http.session.secure` | boolean | false | whether or not the Otoroshi backoffice session will be served over https only |\n| `play.http.session.httpOnly` | boolean | true | whether or not the Otoroshi backoffice session will be accessible from Javascript |\n| `play.http.session.maxAge` | number | 259200000 | the number of seconds before Otoroshi backoffice session expired |\n| `play.http.session.domain` | string | \".oto.tools\" | the domain on which the Otoroshi backoffice session is authorized |\n| `play.http.session.cookieName` | string | \"otoroshi-session\" | the name of the Otoroshi backoffice session |\n| `play.ws.play.ws.useragent` | string | \"Otoroshi\" | the user agent sent by Otoroshi if not present on the original http request |\n| `play.server.https.keyStore.path` | string | | the path to the keystore containing the private key and certificate, if not provided generates a keystore for you |\n| `play.server.https.keyStore.type` | string | JKS | the key store type, defaults to JKS |\n| `play.server.https.keyStore.password` | string | '' | the password, defaults to a blank password |\n| `play.server.https.keyStore.algorithm` | string | | the key store algorithm, defaults to the platforms default algorithm |\n\n## More config. options\n\nSee https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/base.conf and https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/application.conf\n\nif you want to configure https on your Otoroshi server, just read [PlayFramework documentation about it](https://www.playframework.com/documentation/2.6.x/ConfiguringHttps)\n\n## Example of a custom. configuration file\n\n```conf\ninclude \"application.conf\"\n\nhttp.port = 8080\n\napp {\n storage = \"file\"\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) " + }, + { + "name": "datastore.md", + "id": "/firstrun/datastore.md", + "url": "/firstrun/datastore.html", + "title": "Choose your datastore", + "content": "# Choose your datastore\n\nRight now, Otoroshi supports multiple datastore.\n\nYou can choose one datastore over another depending on your use case.\n\nAvailable datastores are the following :\n\n* in memory\n* redis\n* cassandra (experimental support, should be used in cluster mode for leaders)\n* postgresql or any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)\n* filedb (not suitable for production usage)\n\nThe **filedb** datastore is pretty handy for testing purposes, but is not supposed to be used in production mode.\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. You can check the clustering documentation to find more about it.\n\nThe **redis** datastore is quite nice when you want to easily deploy several Otoroshi instances.\n\nIf you need a datastore more scalable than redis, then you can use the **postgresql** or **cassandra** datastore.\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "env.md", + "id": "/firstrun/env.md", + "url": "/firstrun/env.html", + "title": "Config. with ENVs", + "content": "# Config. with ENVs\n\nNow that you know @ref:[how to configure Otoroshi with the config. file](./configfile.md) every property in the following block can be overriden by an environment variable (an env. variable is written like `${?ENV_VARIABLE}`).\n\n## Reference configuration for env. variables\n\n@@snip [reference-env.conf](../snippets/reference-env.conf) \n" + }, + { + "name": "host.md", + "id": "/firstrun/host.md", + "url": "/firstrun/host.html", + "title": "Setup your hosts", + "content": "# Setup your hosts\n\nBy default, Otoroshi starts with domain `oto.tools` that targets `127.0.0.1`. Of course you can change the domain, you have to add the values in your `/etc/hosts` file according to the setting you put in Otoroshi configuration\n\n* `app.domain` => `oto.tools`\n* `app.backoffice.subdomain` => `otoroshi`\n* `app.privateapps.subdomain` => `privateapps`\n* `app.adminapi.exposedSubdomain` => `otoroshi-api`\n* `app.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 -Dapp.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 `app.domain` and the settings listed on this page and in the * @ref:[Config. with files page](./configfile.md) that serve Otoroshi API and UI on `http://otoroshi-api.${app.domain}` and `http://otoroshi.${app.domain}`.\nOnce the descriptor is saved in database, if you want to change `app.domain`, you'll have to edit the descriptor in the database or restart Otoroshi with an empty database.\n@@@\n" + }, + { + "name": "index.md", + "id": "/firstrun/index.md", + "url": "/firstrun/index.html", + "title": "First run", + "content": "# First run\n\nNow that you have your own distro of Otoroshi, it's time to run it. \n\nBut before doing so, you'll have to make some choices about some essential stuff in order to have your own customized version of Otoroshi.\n\nLet's start with the datastore\n\n\n@@@ index\n\n* [choose a datastore](./datastore.md)\n* [use custom config file](./configfile.md)\n* [use ENV](./env.md)\n* [initial state](./initialstate.md)\n* [Hosts](./host.md)\n* [Run](./run.md)\n\n@@@" + }, + { + "name": "initialstate.md", + "id": "/firstrun/initialstate.md", + "url": "/firstrun/initialstate.html", + "title": "Import initial state", + "content": "# Import initial state\n\nNow you are almost ready to run Otoroshi for the first time, but maybe you want to import data from previous Otoroshi installation in your current datastore.\n\nTo do that, you need to add the `app.importFrom` setting to the Otoroshi configuration (of `$APP_IMPORT_FROM` env).\n\nIt can be a file path or a URL\n\n## Example of export\n\n```json\n{\n \"config\": {\n \"lines\": [\"prod\"], \n \"limitConcurrentRequests\": true,\n \"maxConcurrentRequests\": 500,\n \"useCircuitBreakers\": true,\n \"apiReadOnly\": false,\n \"registerFromCleverHook\": false,\n \"u2fLoginOnly\": true,\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"throttlingQuota\": 100000,\n \"perIpThrottlingQuota\": 500,\n \"analyticsEventsUrl\": null,\n \"analyticsWebhooks\": [],\n \"alertsWebhooks\": [],\n \"alertsEmails\": [],\n \"endlessIpAddresses\": []\n },\n \"admins\": [],\n \"simpleAdmins\": [\n {\n \"username\": \"admin@otoroshi.io\",\n \"password\": \"xxxxxxxxxxxxxxxxx\",\n \"label\": \"Otoroshi Admin\",\n \"createdAt\": 1493971715708\n }\n ],\n \"serviceGroups\": [\n {\n \"id\": \"default\",\n \"name\": \"default-group\",\n \"description\": \"The default group\"\n },\n {\n \"id\": \"admin-api-group\",\n \"name\": \"Otoroshi Admin Api group\",\n \"description\": \"No description\"\n }\n ],\n \"apiKeys\": [\n {\n \"clientId\": \"admin-api-apikey-id\",\n \"clientSecret\": \"admin-api-apikey-secret\",\n \"clientName\": \"Otoroshi Backoffice ApiKey\",\n \"authorizedEntities\": [\"group_admin-api-group\"],\n \"enabled\": true,\n \"throttlingQuota\": 10000000,\n \"dailyQuota\": 10000000,\n \"monthlyQuota\": 10000000,\n \"metadata\": {}\n }\n ],\n \"serviceDescriptors\": [\n {\n \"id\": \"admin-api-service\",\n \"groupId\": \"admin-api-group\",\n \"name\": \"otoroshi-admin-api\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"otoroshi-api\",\n \"targets\": [\n {\n \"host\": \"localhost:8080\",\n \"scheme\": \"http\"\n }\n ],\n \"root\": \"/\",\n \"enabled\": true,\n \"privateApp\": false,\n \"forceHttps\": false,\n \"maintenanceMode\": false,\n \"buildMode\": false,\n \"enforceSecureCommunication\": true,\n \"publicPatterns\": [],\n \"privatePatterns\": [],\n \"additionalHeaders\": {\n \"Host\": \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"matchingHeaders\": {},\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"api\": {\n \"exposeApi\": false\n },\n \"healthCheck\": {\n \"enabled\": false,\n \"url\": \"/\"\n },\n \"metadata\": {}\n }\n ],\n \"errorTemplates\": []\n}\n```\n" + }, + { + "name": "run.md", + "id": "/firstrun/run.md", + "url": "/firstrun/run.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\nunzip otoroshi-dist.zip\ncd otoroshi-vx.x.x\n./bin/otoroshi\n```\n\n## From .jar file\n\nFor Java 8 & Java 11\n\n```sh\njava -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](../firstrun/configfile.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](../firstrun/env.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 -Dapp.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 -Dapp.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 -Dapp.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": "frombinaries.md", + "id": "/getotoroshi/frombinaries.md", + "url": "/getotoroshi/frombinaries.html", + "title": "From binaries", + "content": "# From binaries\n\nIf you want to download the last version of Otoroshi and its CLI, you can grab them from the release page of the Otoroshi github page :\n\nGo to https://github.com/MAIF/otoroshi/releases and get the last version of the `otoroshi-dist.zip` file or `otoroshi.jar` file\n" + }, + { + "name": "fromdocker.md", + "id": "/getotoroshi/fromdocker.md", + "url": "/getotoroshi/fromdocker.html", + "title": "From docker", + "content": "# From docker\n\nIf you're a Docker aficionado, Otoroshi is provided as a Docker image that your can pull directly from Official repos.\n\nfirst, fetch the last Docker image of Otoroshi :\n\n```sh\ndocker pull maif/otoroshi:1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:latest\n# or \ndocker pull maif/otoroshi:jdk8-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk11-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk12-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk13-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk14-1.5.0-rc.2\n```" + }, + { + "name": "fromsources.md", + "id": "/getotoroshi/fromsources.md", + "url": "/getotoroshi/fromsources.html", + "title": "From sources", + "content": "# From sources\n\nto build Otoroshi from sources, you need the following tools :\n\n* git\n* JDK 8\n* SBT\n* node\n* yarn\n\nOnce you've installed all those tools, go to the [Otoroshi github page](https://github.com/MAIF/otoroshi) and clone the sources :\n\n```sh\ngit clone https://github.com/MAIF/otoroshi.git --depth=1\n```\n\nthen you need to run the `build.sh` script to build the documentation, the React UI and the server :\n\n```sh\nsh ./scripts/build.sh\n```\n\nand that's all, you can grab your Otoroshi package at `otoroshi/target/scala-2.12/otoroshi` or `otoroshi/target/universal/`.\n\nFor those who want to build only parts of Otoroshi, read the following.\n\n## Build the documentation only\n\nGo to the `documentation` folder and run :\n\n```sh\nsbt ';clean;paradox'\n```\n\nThe documentation is located at `manual/target/paradox/site/main/`\n\n## Build the React UI\n\nGo to the `otoroshi/javascript` folder and run :\n\n```sh\nyarn install\nyarn build\n```\n\nYou will find the JS bundle at `otoroshi/public/javascripts/bundle/bundle.js`.\n\n## Build the Otoroshi server\n\nGo to the `otoroshi` folder and run :\n\n```sh\nexport SBT_OPTS=\"-Xmx2G -Xss6M\"\nsbt ';clean;compile;dist;assembly'\n```\n\nYou will find your Otoroshi package at `otoroshi/target/scala-2.12/otoroshi` or `otoroshi/target/universal/`.\n" + }, + { + "name": "index.md", + "id": "/getotoroshi/index.md", + "url": "/getotoroshi/index.html", + "title": "Get Otoroshi", + "content": "# Get Otoroshi\n\nThere are several ways to get Otoroshi to run it on your system.\n\nLet's start with a good old build from sources :)\n\n@@@ index\n\n* [from sources](./fromsources.md)\n* [from binaries](./frombinaries.md)\n* [from docker](./fromdocker.md)\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.0-rc.2/otoroshi.jar)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\n## Installation\n\nYou can download the latest build of Otoroshi as a [fat jar](https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi.jar), as a [zip package](https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi-dist.zip) or as a @ref:[docker image](./getotoroshi/fromdocker.md).\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.0-rc.2/otoroshi.jar'\njava -jar otoroshi.jar\n```\n\nor using docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi:1.5.0-rc.2\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](./quickstart.md) or directly to the @ref:[installation instructions](./getotoroshi/index.md)\n\n## Documentation\n\n* @ref:[About Otoroshi](./about.md)\n* @ref:[Architecture](./archi.md)\n* @ref:[Features](./features.md)\n* @ref:[Try Otoroshi in 5 minutes](./quickstart.md)\n* @ref:[Get Otoroshi](./getotoroshi/index.md)\n* @ref:[First run](./firstrun/index.md)\n* @ref:[Setup Otoroshi](./setup/index.md)\n* @ref:[Using Otoroshi](./usage/index.md)\n* @ref:[Third party Integrations](./integrations/index.md)\n* @ref:[Detailed topics](./topics/index.md)\n* @ref:[Admin REST API](./api.md)\n* @ref:[Deploy to production](./deploy/index.md)\n* @ref:[Developing Otoroshi](./dev.md)\n\n## Discussion\n\nJoin the [Otoroshi](https://gitter.im/MAIF/otoroshi) channel on the [MAIF Gitter](https://gitter.im/MAIF)\n\n## Sources\n\nThe sources of Otoroshi are available on [Github](https://github.com/MAIF/otoroshi).\n\n## Logo\n\nYou can find the official Otoroshi logo [on GitHub](https://github.com/MAIF/otoroshi/blob/master/resources/otoroshi-logo.png). 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 [Github Releases](https://github.com/MAIF/otoroshi/releases) page. A condensed version of the changelog is available on [github]((https://github.com/MAIF/otoroshi/CHANGELOG.md)\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 [Apache 2 License](https://opensource.org/licenses/Apache-2.0) \n\n@@@ index\n\n* [About Otoroshi](about.md)\n* [Architecture](archi.md)\n* [Features](features.md)\n* [Quickstart](quickstart.md)\n* [Get otoroshi](getotoroshi/index.md)\n* [First run](firstrun/index.md)\n* [Setup](setup/index.md)\n* [Using Otoroshi](usage/index.md)\n* [Integrations](integrations/index.md)\n* [Detailed topics](topics/index.md)\n* [Admin REST API](api.md)\n* [Deploy to production](deploy/index.md)\n* [Developing Otoroshi](./dev.md)\n* [Otoroshi plugins](./plugins/index.md) \n\n@@@\n" + }, + { + "name": "analytics.md", + "id": "/integrations/analytics.md", + "url": "/integrations/analytics.html", + "title": "Analytics", + "content": "# Analytics\n\nEach action and request on Otoroshi creates events that can be sent outside of Otoroshi for further usage. Those events can be sent using a webhook and/or through a Kafka topic.\n\n## Push events to Elasticsearch\n\n@@@ warning\nOtoroshi supports only Elasticsearch versions under 7.0\n@@@\n\nYou can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (write)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Read events from Elasticsearch\n\nYou can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic dashboard datasource (read)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Push events to WebHooks\n\nGo to `settings (cog icon) / Danger Zone` and expand the `Analytics: Webhooks` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nHere you can configure the URL of the webhook and its headers if needed.\n\n## Push events to Kafka\n\nEvents can also be sent through a Kafka topic. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Kafka` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form, default values for topic names are :\n\n* `otoroshi-alerts`\n* `otoroshi-analytics`\n* `otoroshi-audits`\n\n@@@ warning\nIf you use trustore/keystore to access your kafka instances, the paths should be absolute and refers to host paths. You can also choose a client certificate from otoroshi for client authentication.\n@@@\n" + }, + { + "name": "clevercloud.md", + "id": "/integrations/clevercloud.md", + "url": "/integrations/clevercloud.html", + "title": "Clever Cloud", + "content": "# Clever Cloud\n\nOtoroshi provides an integration with Clever Cloud to create easily services based on application deployed on your Clever Cloud account.\nGo to `settings (cog icon) / Danger Zone` and expand the `CleverCloud settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form with your CleverCloud credentials (https://www.clever-cloud.com/doc/clever-cloud-apis/cc-api/) and your CleverCloud `organization id`.\n\nOnce it's done, you will see a new menu in the side bar.\n\n@@@ div { .centered-img }\n\n@@@\n\nIf you click on it, you'll see a page listing all your apps deployed on Clever Cloud with buttons to create new services with the app as the target.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou will also see a new button in the `Target` section of services to attach Clever Cloud applications as target for a service.\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "index.md", + "id": "/integrations/index.md", + "url": "/integrations/index.html", + "title": "Third party Integrations", + "content": "# Third party Integrations\n\nOtoroshi provides some settings to interact with some third party systems.\n\n@@@ index\n\n* [Analytics](./analytics.md)\n* [Mailgun / Mailjet](./mailgun.md)\n* [StatsD / Datadog](./statsd.md)\n* [clevercloud](./clevercloud.md)\n\n@@@\n" + }, + { + "name": "mailgun.md", + "id": "/integrations/mailgun.md", + "url": "/integrations/mailgun.html", + "title": "Mailgun", + "content": "# Mailgun\n\nIf you want to receive Otoroshi alert by emails, you have to configure Otoroshi with your Mailgun credentials. Go to `settings (cog icon) / Danger Zone` and expand the `Mailgun settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form with provided information on the `domain informations` page on Mailgun located at https://app.mailgun.com/app/domains/my.domain.\n\nThen, expand the `Alert settings` section and add email addresses separated by comma in the `Alert emails` field. **Don't forget to save.**\n\n@@@ div { .centered-img }\n\n@@@\n\n# Mailjet\n\nOtoroshi also supports Mailjet. Just select `Mailjet` in `Mailer settings type` and fill the requested fields." + }, + { + "name": "statsd.md", + "id": "/integrations/statsd.md", + "url": "/integrations/statsd.html", + "title": "StatsD / Datadog", + "content": "# StatsD / Datadog\n\nOtoroshi provides a StatsD integration to monitor some technical metrics across all your Otoroshi instances.\nGo to `settings (cog icon) / Danger Zone` and expand the `Statsd settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nAdd the host and port of the Statsd agent on your system.\nIf you're using Datadog, don't forget to check the `Datadog` switch.\n" + }, + { + "name": "index.md", + "id": "/plugins/index.md", + "url": "/plugins/index.html", + "title": "Otoroshi plugins", + "content": "# Otoroshi plugins\n\nOtoroshi provides some plugins out of the box\n\n* @ref:[Access log (CLF)](./otoroshi-plugins-accesslog-accesslog.md)\n* @ref:[Access log (JSON)](./otoroshi-plugins-accesslog-accesslogjson.md)\n* @ref:[Allowed users only](./otoroshi-plugins-users-hasallowedusersvalidator.md)\n* @ref:[Apikey auth module](./otoroshi-plugins-apikeys-apikeyauthmodule.md)\n* @ref:[Apikey from Biscuit token extractor](./otoroshi-plugins-biscuit-biscuitextractor.md)\n* @ref:[Basic Auth. caller](./otoroshi-plugins-authcallers-basicauthcaller.md)\n* @ref:[Biscuit token validator](./otoroshi-plugins-biscuit-biscuitvalidator.md)\n* @ref:[Body logger](./otoroshi-plugins-loggers-bodylogger.md)\n* @ref:[Client Certificate + Api Key only](./otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md)\n* @ref:[Client Certificate Only](./otoroshi-plugins-clientcert-hasclientcertvalidator.md)\n* @ref:[Client Credential Flow ApiKey extractor](./otoroshi-plugins-apikeys-clientcredentialflowextractor.md)\n* @ref:[Client Credential Service](./otoroshi-plugins-apikeys-clientcredentialservice.md)\n* @ref:[Client certificate as apikey](./otoroshi-plugins-apikeys-certificateasapikey.md)\n* @ref:[Client certificate header](./otoroshi-plugins-clientcert-clientcertchainheader.md)\n* @ref:[Client certificate matching](./otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md)\n* @ref:[Client certificate matching (over http)](./otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md)\n* @ref:[Defer Responses](./otoroshi-plugins-defer-deferplugin.md)\n* @ref:[Envoy Control Plane (experimental)](./otoroshi-plugins-envoy-envoycontrolplane.md)\n* @ref:[External Http Validator](./otoroshi-plugins-external-externalhttpvalidator.md)\n* @ref:[Geolocation details extractor (using IpStack api)](./otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md)\n* @ref:[Geolocation details extractor (using Maxmind db)](./otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md)\n* @ref:[Geolocation endpoint](./otoroshi-plugins-geoloc-geolocationinfoendpoint.md)\n* @ref:[Geolocation header](./otoroshi-plugins-geoloc-geolocationinfoheader.md)\n* @ref:[Global self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationsink.md)\n* @ref:[HMAC access validator](./otoroshi-plugins-hmac-hmacvalidator.md)\n* @ref:[HMAC caller plugin](./otoroshi-plugins-hmac-hmaccallerplugin.md)\n* @ref:[Html Patcher](./otoroshi-plugins-jsoup-htmlpatcher.md)\n* @ref:[Instance quotas](./otoroshi-plugins-quotas-instancequotas.md)\n* @ref:[Izanami APIs Proxy](./otoroshi-plugins-izanami-izanamiproxy.md)\n* @ref:[Izanami Canary Campaign](./otoroshi-plugins-izanami-izanamicanary.md)\n* @ref:[Jwt user extractor](./otoroshi-plugins-jwt-jwtuserextractor.md)\n* @ref:[Kafka access log](./otoroshi-plugins-accesslog-kafkaaccesslog.md)\n* @ref:[Kubernetes Ingress Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md)\n* @ref:[Kubernetes Otoroshi CRDs Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md)\n* @ref:[Kubernetes admission validator webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md)\n* @ref:[Kubernetes sidecar injector webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md)\n* @ref:[Kubernetes to Otoroshi certs. synchronizer](./otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md)\n* @ref:[Mirroring plugin](./otoroshi-plugins-mirror-mirroringplugin.md)\n* @ref:[OAuth1 caller](./otoroshi-plugins-oauth1-oauth1callerplugin.md)\n* @ref:[OAuth2 caller](./otoroshi-plugins-authcallers-oauth2caller.md)\n* @ref:[OIDC access_token as apikey](./otoroshi-plugins-oidc-oidcaccesstokenasapikey.md)\n* @ref:[OIDC access_token validator](./otoroshi-plugins-oidc-oidcaccesstokenvalidator.md)\n* @ref:[OIDC headers](./otoroshi-plugins-oidc-oidcheaders.md)\n* @ref:[Otoroshi certs. to Kubernetes secrets synchronizer](./otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md)\n* @ref:[Prometheus Endpoint](./otoroshi-plugins-metrics-prometheusendpoint.md)\n* @ref:[Prometheus Service Metrics](./otoroshi-plugins-metrics-prometheusservicemetrics.md)\n* @ref:[Public quotas](./otoroshi-plugins-quotas-servicequotas.md)\n* @ref:[Response Cache](./otoroshi-plugins-cache-responsecache.md)\n* @ref:[Security Txt](./otoroshi-plugins-security-securitytxt.md)\n* @ref:[Self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md)\n* @ref:[Service Metrics](./otoroshi-plugins-metrics-servicemetrics.md)\n* @ref:[Service discovery target selector (service discovery)](./otoroshi-plugins-discovery-discoverytargetsselector.md)\n* @ref:[Static Response](./otoroshi-plugins-static-staticresponse.md)\n* @ref:[User-Agent details extractor](./otoroshi-plugins-useragent-useragentextractor.md)\n* @ref:[User-Agent endpoint](./otoroshi-plugins-useragent-useragentinfoendpoint.md)\n* @ref:[User-Agent header](./otoroshi-plugins-useragent-useragentinfoheader.md)\n* @ref:[Workflow endpoint](./otoroshi-plugins-workflow-workflowendpoint.md)\n* @ref:[Workflow job](./otoroshi-plugins-workflow-workflowjob.md)\n\n@@@ index\n\n* [Access log (CLF)](./otoroshi-plugins-accesslog-accesslog.md)\n* [Access log (JSON)](./otoroshi-plugins-accesslog-accesslogjson.md)\n* [Allowed users only](./otoroshi-plugins-users-hasallowedusersvalidator.md)\n* [Apikey auth module](./otoroshi-plugins-apikeys-apikeyauthmodule.md)\n* [Apikey from Biscuit token extractor](./otoroshi-plugins-biscuit-biscuitextractor.md)\n* [Basic Auth. caller](./otoroshi-plugins-authcallers-basicauthcaller.md)\n* [Biscuit token validator](./otoroshi-plugins-biscuit-biscuitvalidator.md)\n* [Body logger](./otoroshi-plugins-loggers-bodylogger.md)\n* [Client Certificate + Api Key only](./otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md)\n* [Client Certificate Only](./otoroshi-plugins-clientcert-hasclientcertvalidator.md)\n* [Client Credential Flow ApiKey extractor](./otoroshi-plugins-apikeys-clientcredentialflowextractor.md)\n* [Client Credential Service](./otoroshi-plugins-apikeys-clientcredentialservice.md)\n* [Client certificate as apikey](./otoroshi-plugins-apikeys-certificateasapikey.md)\n* [Client certificate header](./otoroshi-plugins-clientcert-clientcertchainheader.md)\n* [Client certificate matching](./otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md)\n* [Client certificate matching (over http)](./otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md)\n* [Defer Responses](./otoroshi-plugins-defer-deferplugin.md)\n* [Envoy Control Plane (experimental)](./otoroshi-plugins-envoy-envoycontrolplane.md)\n* [External Http Validator](./otoroshi-plugins-external-externalhttpvalidator.md)\n* [Geolocation details extractor (using IpStack api)](./otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md)\n* [Geolocation details extractor (using Maxmind db)](./otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md)\n* [Geolocation endpoint](./otoroshi-plugins-geoloc-geolocationinfoendpoint.md)\n* [Geolocation header](./otoroshi-plugins-geoloc-geolocationinfoheader.md)\n* [Global self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationsink.md)\n* [HMAC access validator](./otoroshi-plugins-hmac-hmacvalidator.md)\n* [HMAC caller plugin](./otoroshi-plugins-hmac-hmaccallerplugin.md)\n* [Html Patcher](./otoroshi-plugins-jsoup-htmlpatcher.md)\n* [Instance quotas](./otoroshi-plugins-quotas-instancequotas.md)\n* [Izanami APIs Proxy](./otoroshi-plugins-izanami-izanamiproxy.md)\n* [Izanami Canary Campaign](./otoroshi-plugins-izanami-izanamicanary.md)\n* [Jwt user extractor](./otoroshi-plugins-jwt-jwtuserextractor.md)\n* [Kafka access log](./otoroshi-plugins-accesslog-kafkaaccesslog.md)\n* [Kubernetes Ingress Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md)\n* [Kubernetes Otoroshi CRDs Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md)\n* [Kubernetes admission validator webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md)\n* [Kubernetes sidecar injector webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md)\n* [Kubernetes to Otoroshi certs. synchronizer](./otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md)\n* [Mirroring plugin](./otoroshi-plugins-mirror-mirroringplugin.md)\n* [OAuth1 caller](./otoroshi-plugins-oauth1-oauth1callerplugin.md)\n* [OAuth2 caller](./otoroshi-plugins-authcallers-oauth2caller.md)\n* [OIDC access_token as apikey](./otoroshi-plugins-oidc-oidcaccesstokenasapikey.md)\n* [OIDC access_token validator](./otoroshi-plugins-oidc-oidcaccesstokenvalidator.md)\n* [OIDC headers](./otoroshi-plugins-oidc-oidcheaders.md)\n* [Otoroshi certs. to Kubernetes secrets synchronizer](./otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md)\n* [Prometheus Endpoint](./otoroshi-plugins-metrics-prometheusendpoint.md)\n* [Prometheus Service Metrics](./otoroshi-plugins-metrics-prometheusservicemetrics.md)\n* [Public quotas](./otoroshi-plugins-quotas-servicequotas.md)\n* [Response Cache](./otoroshi-plugins-cache-responsecache.md)\n* [Security Txt](./otoroshi-plugins-security-securitytxt.md)\n* [Self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md)\n* [Service Metrics](./otoroshi-plugins-metrics-servicemetrics.md)\n* [Service discovery target selector (service discovery)](./otoroshi-plugins-discovery-discoverytargetsselector.md)\n* [Static Response](./otoroshi-plugins-static-staticresponse.md)\n* [User-Agent details extractor](./otoroshi-plugins-useragent-useragentextractor.md)\n* [User-Agent endpoint](./otoroshi-plugins-useragent-useragentinfoendpoint.md)\n* [User-Agent header](./otoroshi-plugins-useragent-useragentinfoheader.md)\n* [Workflow endpoint](./otoroshi-plugins-workflow-workflowendpoint.md)\n* [Workflow job](./otoroshi-plugins-workflow-workflowjob.md)\n\n@@@\n\n\n" + }, + { + "name": "otoroshi-plugins-accesslog-accesslog.md", + "id": "/plugins/otoroshi-plugins-accesslog-accesslog.md", + "url": "/plugins/otoroshi-plugins-accesslog-accesslog.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-accesslog-accesslogjson.md", + "id": "/plugins/otoroshi-plugins-accesslog-accesslogjson.md", + "url": "/plugins/otoroshi-plugins-accesslog-accesslogjson.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-accesslog-kafkaaccesslog.md", + "id": "/plugins/otoroshi-plugins-accesslog-kafkaaccesslog.md", + "url": "/plugins/otoroshi-plugins-accesslog-kafkaaccesslog.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-apikeys-apikeyauthmodule.md", + "id": "/plugins/otoroshi-plugins-apikeys-apikeyauthmodule.md", + "url": "/plugins/otoroshi-plugins-apikeys-apikeyauthmodule.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-apikeys-certificateasapikey.md", + "id": "/plugins/otoroshi-plugins-apikeys-certificateasapikey.md", + "url": "/plugins/otoroshi-plugins-apikeys-certificateasapikey.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-apikeys-clientcredentialflowextractor.md", + "id": "/plugins/otoroshi-plugins-apikeys-clientcredentialflowextractor.md", + "url": "/plugins/otoroshi-plugins-apikeys-clientcredentialflowextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-apikeys-clientcredentialservice.md", + "id": "/plugins/otoroshi-plugins-apikeys-clientcredentialservice.md", + "url": "/plugins/otoroshi-plugins-apikeys-clientcredentialservice.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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" + }, + { + "name": "otoroshi-plugins-authcallers-basicauthcaller.md", + "id": "/plugins/otoroshi-plugins-authcallers-basicauthcaller.md", + "url": "/plugins/otoroshi-plugins-authcallers-basicauthcaller.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-authcallers-oauth2caller.md", + "id": "/plugins/otoroshi-plugins-authcallers-oauth2caller.md", + "url": "/plugins/otoroshi-plugins-authcallers-oauth2caller.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-biscuit-biscuitextractor.md", + "id": "/plugins/otoroshi-plugins-biscuit-biscuitextractor.md", + "url": "/plugins/otoroshi-plugins-biscuit-biscuitextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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 \"secret\" : \"secret\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"sealed\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n" + }, + { + "name": "otoroshi-plugins-biscuit-biscuitvalidator.md", + "id": "/plugins/otoroshi-plugins-biscuit-biscuitvalidator.md", + "url": "/plugins/otoroshi-plugins-biscuit-biscuitvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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 \"secret\" : \"secret\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"sealed\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n" + }, + { + "name": "otoroshi-plugins-cache-responsecache.md", + "id": "/plugins/otoroshi-plugins-cache-responsecache.md", + "url": "/plugins/otoroshi-plugins-cache-responsecache.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-clientcert-clientcertchainheader.md", + "id": "/plugins/otoroshi-plugins-clientcert-clientcertchainheader.md", + "url": "/plugins/otoroshi-plugins-clientcert-clientcertchainheader.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md", + "id": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md", + "url": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md", + "id": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md", + "url": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md", + "id": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md", + "url": "/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-clientcert-hasclientcertvalidator.md", + "id": "/plugins/otoroshi-plugins-clientcert-hasclientcertvalidator.md", + "url": "/plugins/otoroshi-plugins-clientcert-hasclientcertvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-defer-deferplugin.md", + "id": "/plugins/otoroshi-plugins-defer-deferplugin.md", + "url": "/plugins/otoroshi-plugins-defer-deferplugin.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-discovery-discoveryselfregistrationsink.md", + "id": "/plugins/otoroshi-plugins-discovery-discoveryselfregistrationsink.md", + "url": "/plugins/otoroshi-plugins-discovery-discoveryselfregistrationsink.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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" + }, + { + "name": "otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md", + "id": "/plugins/otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md", + "url": "/plugins/otoroshi-plugins-discovery-discoveryselfregistrationtransformer.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-discovery-discoverytargetsselector.md", + "id": "/plugins/otoroshi-plugins-discovery-discoverytargetsselector.md", + "url": "/plugins/otoroshi-plugins-discovery-discoverytargetsselector.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-envoy-envoycontrolplane.md", + "id": "/plugins/otoroshi-plugins-envoy-envoycontrolplane.md", + "url": "/plugins/otoroshi-plugins-envoy-envoycontrolplane.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-external-externalhttpvalidator.md", + "id": "/plugins/otoroshi-plugins-external-externalhttpvalidator.md", + "url": "/plugins/otoroshi-plugins-external-externalhttpvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-geoloc-geolocationinfoendpoint.md", + "id": "/plugins/otoroshi-plugins-geoloc-geolocationinfoendpoint.md", + "url": "/plugins/otoroshi-plugins-geoloc-geolocationinfoendpoint.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-geoloc-geolocationinfoheader.md", + "id": "/plugins/otoroshi-plugins-geoloc-geolocationinfoheader.md", + "url": "/plugins/otoroshi-plugins-geoloc-geolocationinfoheader.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md", + "id": "/plugins/otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md", + "url": "/plugins/otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md", + "id": "/plugins/otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md", + "url": "/plugins/otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-hmac-hmaccallerplugin.md", + "id": "/plugins/otoroshi-plugins-hmac-hmaccallerplugin.md", + "url": "/plugins/otoroshi-plugins-hmac-hmaccallerplugin.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-hmac-hmacvalidator.md", + "id": "/plugins/otoroshi-plugins-hmac-hmacvalidator.md", + "url": "/plugins/otoroshi-plugins-hmac-hmacvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-izanami-izanamicanary.md", + "id": "/plugins/otoroshi-plugins-izanami-izanamicanary.md", + "url": "/plugins/otoroshi-plugins-izanami-izanamicanary.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-izanami-izanamiproxy.md", + "id": "/plugins/otoroshi-plugins-izanami-izanamiproxy.md", + "url": "/plugins/otoroshi-plugins-izanami-izanamiproxy.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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" + }, + { + "name": "otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md", + "id": "/plugins/otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md", + "url": "/plugins/otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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" + }, + { + "name": "otoroshi-plugins-jsoup-htmlpatcher.md", + "id": "/plugins/otoroshi-plugins-jsoup-htmlpatcher.md", + "url": "/plugins/otoroshi-plugins-jsoup-htmlpatcher.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-jwt-jwtuserextractor.md", + "id": "/plugins/otoroshi-plugins-jwt-jwtuserextractor.md", + "url": "/plugins/otoroshi-plugins-jwt-jwtuserextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-loggers-bodylogger.md", + "id": "/plugins/otoroshi-plugins-loggers-bodylogger.md", + "url": "/plugins/otoroshi-plugins-loggers-bodylogger.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-metrics-prometheusendpoint.md", + "id": "/plugins/otoroshi-plugins-metrics-prometheusendpoint.md", + "url": "/plugins/otoroshi-plugins-metrics-prometheusendpoint.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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" + }, + { + "name": "otoroshi-plugins-metrics-prometheusservicemetrics.md", + "id": "/plugins/otoroshi-plugins-metrics-prometheusservicemetrics.md", + "url": "/plugins/otoroshi-plugins-metrics-prometheusservicemetrics.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-metrics-servicemetrics.md", + "id": "/plugins/otoroshi-plugins-metrics-servicemetrics.md", + "url": "/plugins/otoroshi-plugins-metrics-servicemetrics.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-mirror-mirroringplugin.md", + "id": "/plugins/otoroshi-plugins-mirror-mirroringplugin.md", + "url": "/plugins/otoroshi-plugins-mirror-mirroringplugin.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-oauth1-oauth1callerplugin.md", + "id": "/plugins/otoroshi-plugins-oauth1-oauth1callerplugin.md", + "url": "/plugins/otoroshi-plugins-oauth1-oauth1callerplugin.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-oidc-oidcaccesstokenasapikey.md", + "id": "/plugins/otoroshi-plugins-oidc-oidcaccesstokenasapikey.md", + "url": "/plugins/otoroshi-plugins-oidc-oidcaccesstokenasapikey.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-oidc-oidcaccesstokenvalidator.md", + "id": "/plugins/otoroshi-plugins-oidc-oidcaccesstokenvalidator.md", + "url": "/plugins/otoroshi-plugins-oidc-oidcaccesstokenvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-oidc-oidcheaders.md", + "id": "/plugins/otoroshi-plugins-oidc-oidcheaders.md", + "url": "/plugins/otoroshi-plugins-oidc-oidcheaders.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-quotas-instancequotas.md", + "id": "/plugins/otoroshi-plugins-quotas-instancequotas.md", + "url": "/plugins/otoroshi-plugins-quotas-instancequotas.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-quotas-servicequotas.md", + "id": "/plugins/otoroshi-plugins-quotas-servicequotas.md", + "url": "/plugins/otoroshi-plugins-quotas-servicequotas.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-security-securitytxt.md", + "id": "/plugins/otoroshi-plugins-security-securitytxt.md", + "url": "/plugins/otoroshi-plugins-security-securitytxt.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-static-staticresponse.md", + "id": "/plugins/otoroshi-plugins-static-staticresponse.md", + "url": "/plugins/otoroshi-plugins-static-staticresponse.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-useragent-useragentextractor.md", + "id": "/plugins/otoroshi-plugins-useragent-useragentextractor.md", + "url": "/plugins/otoroshi-plugins-useragent-useragentextractor.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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" + }, + { + "name": "otoroshi-plugins-useragent-useragentinfoendpoint.md", + "id": "/plugins/otoroshi-plugins-useragent-useragentinfoendpoint.md", + "url": "/plugins/otoroshi-plugins-useragent-useragentinfoendpoint.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-useragent-useragentinfoheader.md", + "id": "/plugins/otoroshi-plugins-useragent-useragentinfoheader.md", + "url": "/plugins/otoroshi-plugins-useragent-useragentinfoheader.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-users-hasallowedusersvalidator.md", + "id": "/plugins/otoroshi-plugins-users-hasallowedusersvalidator.md", + "url": "/plugins/otoroshi-plugins-users-hasallowedusersvalidator.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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" + }, + { + "name": "otoroshi-plugins-workflow-workflowendpoint.md", + "id": "/plugins/otoroshi-plugins-workflow-workflowendpoint.md", + "url": "/plugins/otoroshi-plugins-workflow-workflowendpoint.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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" + }, + { + "name": "otoroshi-plugins-workflow-workflowjob.md", + "id": "/plugins/otoroshi-plugins-workflow-workflowjob.md", + "url": "/plugins/otoroshi-plugins-workflow-workflowjob.html", + "title": "", + "content": "\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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" + }, + { + "name": "quickstart.md", + "id": "/quickstart.md", + "url": "/quickstart.html", + "title": "Try Otoroshi in 5 minutes", + "content": "# Try Otoroshi in 5 minutes\n\nwhat you will need :\n\n* JDK 11\n* curl\n* jq\n* 5 minutes of free time\n\n## The elevator pitch\n\nOtoroshi is an awesome reverse proxy built with Scala that handles all the calls to and between your microservices without service locator and lets you change configuration dynamically at runtime.\n\n## Download otoroshi\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi.jar'\n```\n\nIf you don’t/can’t have these tools on your machine, you can start a sandboxed environment using here with the following command\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi\n```\n\n## Start otoroshi\n\nto start otoroshi, just run the following command \n\n```sh\njava -jar otoroshi.jar\n```\n\nthis will start an in-memory otoroshi instance with a generated password that will be printed in the logs. You can set the password with the following flags\n\n```sh\njava -Dapp.adminLogin=admin@foo.bar -Dapp.adminPassword=password -jar otoroshi.jar\n```\n\nif you want to have otoroshi content persisted between launch without having to setup a datastore, just usse the following flag\n\n```sh\njava -Dapp.storage=file -jar otoroshi.jar\n```\n\nas the result, you will see something like\n\n```log\n$ java -jar otoroshi.jar\n\n[info] otoroshi-env - Otoroshi version 1.5.0-rc.2\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[warn] otoroshi-env - Scripting is enabled on this Otoroshi instance !\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 / xol1Kwjzqe9OXjqDxxPPbPb9p0BPjhCO\n[info] play.api.Play - Application started (Prod)\n[info] otoroshi-script-manager - Compiling and starting scripts ...\n[info] otoroshi-script-manager - Finding and starting plugins ...\n[info] otoroshi-script-manager - Compiling and starting scripts done in 18 ms.\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-script-manager - Finding and starting plugins done in 4681 ms.\n[info] otoroshi-env - Generating CA certificate for Otoroshi self signed certificates ...\n[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...\n```\n\n## Log into the admin UI\n\njust go to http://otoroshi.oto.tools:8080 and log in with the credentials printed in the logs\n\n## Create you first service\n\nto create your first service you can either do it using the admin UI or using the admin API. Let's use the admin API.\n\nBy default, otoroshi registers an admin apikey with `admin-api-apikey-id:admin-api-apikey-secret` value (those values can be tuned at first startup). Of course you can create your own with\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/apikeys/_template \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n -d '{\n \"clientId\": \"quickstart\",\n \"clientSecret\": \"secret\",\n \"clientName\": \"quickstart-apikey\",\n \"authorizedEntities\": [\"group_admin-api-group\"]\n}' | jq\n```\n\nnow let create a new service to proxy `https://maif.gitub.io` on domain `maif.oto.tools`. This service will be public and will not require an apikey to pass\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/_template \\\n -u quickstart:secret \\\n -d '{\n \"name\": \"quickstart-service\", \n \"hosts\": [\"maif.oto.tools\"], \n \"targets\": [{ \"host\": \"maif.github.io\", \"scheme\": \"https\" }], \n \"publicPatterns\": [\"/.*\"]\n}' | jq\n```\n\nnow just go to `http://maif.oto.tools:8080` to check if it works\n\n## Create a service to proxy an api\n\nnow will we proxy the api at `https://aws.random.cat/meow` that returns random cat pictures and make it use apikeys.\n\n```sh\n$ curl https://aws.random.cat/meow | jq\n\n{\n \"file\": \"https://purr.objects-us-east-1.dream.io/i/20161003_163413.jpg\"\n}\n```\n\nFirst let's create the service \n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/_template \\\n -u quickstart:secret \\\n -d '{\n \"id\": \"cats-api\",\n \"name\": \"cats-api\", \n \"hosts\": [\"cats.oto.tools\"], \n \"targets\": [{ \"host\": \"aws.random.cat\", \"scheme\": \"https\" }],\n \"root\": \"/meow\"\n}' | jq\n```\n\nbut if you try to use it, you will have something like :\n\n```sh\n$ curl http://cats.oto.tools:8080 | jq\n\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nthat's because the api is not public and needs apikeys to access it. So let's create an apikey\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/apikeys/_template \\\n -u quickstart:secret \\\n -d '{\n \"clientId\": \"apikey1\",\n \"clientSecret\": \"secret\",\n \"clientName\": \"quickstart-apikey-1\",\n \"authorizedEntities\": [\"group_default\"]\n}' | jq\n``` \n\nand try again\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret | jq\n\n{\n \"file\": \"https://purr.objects-us-east-1.dream.io/i/vICG4.gif\"\n}\n```\n\nnow let's try to play with quotas. First, we need to know what is the current state of the apikey quotas by enabling otoroshi headers about consumptions\n\n```sh\ncurl -X PATCH -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/cats-api \\\n -u quickstart:secret \\\n -d '[\n { \"op\": \"replace\", \"path\": \"/sendOtoroshiHeadersBack\", \"value\": true }\n]' | jq\n```\n\nand retry the call with \n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 200 OK\nDate: Tue, 10 Mar 2020 12:56:08 GMT\nServer: Apache\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\nCache-Control: no-cache, must-revalidate\nOtoroshi-Request-Id: 1237361356529729796\nOtoroshi-Proxy-Latency: 79\nOtoroshi-Upstream-Latency: 416\nOtoroshi-Request-Timestamp: 2020-03-10T13:55:11.195+01:00\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET\nOtoroshi-Daily-Calls-Remaining: 9999998\nOtoroshi-Monthly-Calls-Remaining: 9999998\nContent-Type: application/json\nContent-Length: 71\n\n{\"file\":\"https:\\/\\/purr.objects-us-east-1.dream.io\\/i\\/beerandcat.jpg\"}\n```\n\nnow let's try to allow only 10 request per day on the apikey\n\n```sh\ncurl -X PATCH -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/cats-api/apikeys/apikey1 \\\n -u quickstart:secret \\\n -d '[\n { \"op\": \"replace\", \"path\": \"/dailyQuota\", \"value\": 10 }\n]' | jq\n```\n\nthen try to call you api again\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 200 OK\nDate: Tue, 10 Mar 2020 13:00:01 GMT\nServer: Apache\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\nCache-Control: no-cache, must-revalidate\nOtoroshi-Request-Id: 1237362334930829633\nOtoroshi-Proxy-Latency: 71\nOtoroshi-Upstream-Latency: 92\nOtoroshi-Request-Timestamp: 2020-03-10T13:59:04.456+01:00\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET\nOtoroshi-Daily-Calls-Remaining: 7\nOtoroshi-Monthly-Calls-Remaining: 9999997\nContent-Type: application/json\nContent-Length: 66\n\n{\"file\":\"https:\\/\\/purr.objects-us-east-1.dream.io\\/i\\/C1XNK.jpg\"}\n```\n\neventually you will get something like\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 429 Too Many Requests\nOtoroshi-Error: true\nOtoroshi-Error-Msg: You performed too much requests\nOtoroshi-State-Resp: --\nDate: Tue, 10 Mar 2020 12:59:11 GMT\nContent-Type: application/json\nContent-Length: 52\n\n{\"Otoroshi-Error\":\"You performed too much requests\"}\n```" + }, + { + "name": "admin.md", + "id": "/setup/admin.md", + "url": "/setup/admin.html", + "title": "Manage admin users", + "content": "# Manage admin users\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated and UI may have changed\n@@@\n\n## Create admin user after the first run\n\nClick on the `Create an admin user` warning popup, or go to `settings (cog icon) / Admins`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou will see the list of registered admin users.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register admin.`\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, enter informations about the new admin you want to create.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register Admin`.\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, you can discard the generated admin, confirm, then logout, login with the admin user you have just created and the danger popup will go away\n\n@@@ div { .centered-img }\n\n@@@\n\n## Create admin user with U2F device login\n\nGo to `settings (cog icon) / Admins`, click on `Register Admin`.\n\n@@@ div { .centered-img }\n\n@@@\n\nEnter informations about the new admin you want to create.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register Admin with WebAuthn`.\n\nOtoroshi will ask you to plug your FIDO U2F device and touch it to complete registration.\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ warning\nTo be able to use FIDO U2F devices, Otoroshi must be served over https\n@@@\n\n## Discard admin user\n\nGo to `settings (cog icon) / Admins`, at the bottom of the page, you will see a list of admin users that you can discard. Just click on the `Discard User` button on the right side of the row and confirm that you actually want to discard an admin user.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Admin sessions management\n\nGo to `settings (cog icon) / Admins sessions`, you will see a list of active admin user sessions\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can either discard single sessions one by one using the `Discard Session` on each targeted row of the list or discard all active sessions using the `Discard all sessions` button at the top of the page.\n" + }, + { + "name": "dangerzone.md", + "id": "/setup/dangerzone.md", + "url": "/setup/dangerzone.html", + "title": "Configure the Danger zone", + "content": "# Configure the Danger zone\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated and UI may have changed\n@@@\n\nNow that you have an actual admin account, go to `setting (cog icon) / Danger Zone` in order to configure your Otoroshi instance.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Commons settings\n\nThis part allows you to configure various things :\n\n* `No Auth0 login` => allow you to disabled Auth0 login to the Otoroshi admin dashboard\n* `API read only` => disable `writes` on the Otoroshi admin api\n* `Use HTTP streaming` => use http streaming for each response. It should always be true\n* `Auto link default` => when no group is specified on a service, it will be assigned to default one\n* `Use circuit breakers` => allow usage of circuit breakers for each service\n* `Log analytics on servers` => all analytics will be logged on the servers\n* `Use new http client as the default Http client` => all http call will use the new http client 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` => change the character of endless HTTP responses from `0` to `🖕`\n* `Limit concurrent requests` => allow you to specify a max number of concurrent requests on an Otoroshi instance to avoid overloading\n* `Max concurrent requests` => max allowed number of concurrent requests on an Otoroshi instance to avoid overloading\n* `Max HTTP/1.0 response size` => max size of an HTTP/1.0 responses, because they are memory mapped\n* `Max local events` => number of events stored localy (alerts and audits)\n* `lines` => at least one (`prod`). for other, it will allow you to declare urls like `service.line.domain.tld`. For prod it will be `service.domain.tld`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Whitelist / blacklist settings\n\nOtoroshi is capable of filtering request by ip address, allowing or blocking requests.\n\nOtoroshi also provides a fun feature called `Endless HTTP responses`. If you put an ip address in that field, then, for any http request on Otoroshi, every response will be 128 GB of `0`.\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ note\nNote that you may provide ip address with wildcard like the following `42.42.*.42` or `42.42.42.*` or `42.42.*.*`\n@@@\n\n## Global throttling settings\n\nOtoroshi is capable of managing throttling at a global level. Here you can configure number of authorized requests per second on a single Otoroshi instance and the number of authorized request per second for a unique ip address.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Analytics settings\n\nOne on the major features of Otoroshi is being able of generating internal events. Those events are not stored in Otoroshi's datastore but can be sent using `WebHooks`. You can configure those `WebHooks` from the `Danger Zone`.\n\nOtoroshi is also capable of reading some analytics and displays it from another MAIF product called `Omoïkane`. As Omoikane is not publicly available yet, is capable of storing events in an [Elastic](https://www.elastic.co/) cluster. For more information about analytics and what it does, just go to the @ref:[detailed chapter](../integrations/analytics.md)\n\n## Kafka settings\n\nOne on the major features of Otoroshi is being able of generating internal events. These events are not stored in Otoroshi's datastore but can be sent using a [Kafka message broker](https://kafka.apache.org/). You can configure Kafka access from the `Danger Zone`.\n\nBy default, Otoroshi's alert events will be sent on `otoroshi-alerts` topic, Otoroshi's audit events will be sent on `otoroshi-audits` topic and Otoroshi's traffic events will be sent on `otoroshi-analytics` topic.\n\n@@@ warning\nKeystore and truststore paths are optional local path on the server hosting Otoroshi\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Kafka integration and what it does, just go to the @ref:[detailed chapter](../integrations/analytics.md)\n\n## Alerts settings\n\nEach time a dangerous action or something unusual is performed on Otoroshi, it will create an alert and store it. You can be notified for each of these alerts using `WebHooks` or emails. To do so, just add the `WebHook` URL and optional headers in the `Danger Zone` or any email address you want (you can add more than one email address).\n\nYou can enable mutual authentication via the `Use mTLS` button and add your certificates. The `TLS loose` option will block all untrustful ssl configs, the `TrustAll` option allows any server certificates even the self-signed ones.\n\n@@@ div { .centered-img }\n\n@@@\n\n## StatsD settings\n\nOtoroshi is capable of sending internal metrics to a StatsD agent. Just put the host and port of you StatsD agent in the `Danger Zone` to collect these metrics. If you using [Datadog](https://www.datadoghq.com), don't forget to check the dedicated button :)\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about StatsD integration and what it does, just go to the @ref:[detailed chapter](../integrations/statsd.md)\n\n## Mailer settings\n\nIf you want to send emails for every alert generated by Otoroshi, you need to configure your Mailgun credentials in the `Danger Zone`. These parameters are provided in you Mailgun domain dashboard (i.e. https://app.mailgun.com/app/domains/my.domain.oto.tools) in the information section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Mailgun integration and what it does, just go to the @ref:[detailed chapter](../integrations/mailgun.md)\n\n## CleverCloud settings\n\nAs we built our products to run on Clever-Cloud, Otoroshi has a close integration with Clever-Cloud. In this section of `Danger Zone` you can configure how to access Clever-Cloud API.\n\nTo generate the needed value, please refers to [Clever-Cloud documentation](https://www.clever-cloud.com/doc/clever-cloud-apis/cc-api/)\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Clever-Cloud integration and what it does, just go to the @ref:[detailed chapter](../integrations/clevercloud.md)\n\n## Import / exports and panic mode\n\nFor more details about imports and exports, please go to the @ref:[dedicated chapter](../usage/8-importsexports.md)\n\nAbout panic mode, it's an unusual feature that allows you to discard all current admin. sessions, allows only admin users with U2F devices to log back, and pass the API in read-only mode. Only a person who has access to Otoroshi's datastore will be able to turn it back on.\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "index.md", + "id": "/setup/index.md", + "url": "/setup/index.html", + "title": "Setup Otoroshi", + "content": "# Setup Otoroshi\n\nNow that Otoroshi is running, you are ready to log into the Otoroshi admin dashboard and setup your instance. Just go to :\n\nhttp://otoroshi.oto.tools:8080\n\nand you will see the login page\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ warning\nUse the credentials generated in Otoroshi **logs** during **first run**.\n@@@\n\n@@@ div { .centered-img #first-login-example }\n\n@@@\n\n(of course, you can change this url dependending on the configuration you provided to Otoroshi).\n\nOnce logged in, the first screen you'll see should look like :\n\n@@@ div { .centered-img #first-login }\n\n@@@\n\nAs you can see, Otoroshi is not really happy about you being logged with a generated admin account.\n\nBut we will fix that in the next chapter\n\n@@@ index\n\n* [create admins](./admin.md)\n* [configure danger zone](./dangerzone.md)\n\n@@@\n" + }, + { + "name": "clustering.md", + "id": "/topics/clustering.md", + "url": "/topics/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" + }, + { + "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 topics supported by Otoroshi\n\n@@@ index\n\n* [Chaos engineering with the Snow Monkey](./snow-monkey.md)\n* [JWT Tokens verification](./jwt-verifications.md)\n* [SSL/TLS termination with Otoroshi](./ssl.md)\n* [Mutual TLS with Otoroshi](./mtls.md)\n* [Otoroshi clustering](./clustering.md)\n* [Otoroshi plugins](./plugins.md)\n* [Otoroshi monitoring](./monitoring.md)\n\n@@@\n" + }, + { + "name": "jwt-verifications.md", + "id": "/topics/jwt-verifications.md", + "url": "/topics/jwt-verifications.html", + "title": "JWT Tokens verification", + "content": "# JWT Tokens verification\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. In the Service descriptor page, you can find a `Jwt token Verification` section dedicated to this topic.\n\n## Service descriptor local verifications\n\n@@@ div { .centered-img }\n\n@@@\n\nin this section you can select the type of verification you can choose if the verifier is local to the `Service descriptor` or reference a global one.\n\nYou can also enabled/disable jwt verification and activate strict mode. In strict mode, requests will be rejected if the jwt token is not found.\n\n### Jwt token location\n\nYou can use the `Source` selector to specify where the Jwt token can be found. \n\n* in a query string param\n\n@@@ div { .centered-img }\n\n@@@\n\n* in a header\n\n@@@ div { .centered-img }\n\n@@@\n\n* in a cookie\n\n@@@ div { .centered-img }\n\n@@@\n\n### Jwt signing\n\nYou can use the `Algo.` selector to specify the signing algorithm to use to verifiy the token\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can choose between\n\n* Hmac + SHA256\n* Hmac + SHA384\n* Hmac + SHA512\n* RSA + SHA256\n* RSA + SHA384\n* RSA + SHA512\n* Elliptic Curve + SHA256\n* Elliptic Curve + SHA384\n* Elliptic Curve + SHA512\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can use syntax like `${env.MY_ENV_VAR}` or `${config.my.config.path}` to provide secret/keys values. \n\n\n### Just verify signature and fields value\n\nUsing the `Verif. strategy` selector, you can choose `Verify jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be send to the target just like that.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Re-sign the token\n\nUsing the `Verif. strategy` selector, you can choose `Verify and re-sign jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be re-signed using the settings provided in `Re-sign algo` and will be send to the target.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Transform the token\n\nUsing the `Verif. strategy` selector, you can choose `Verify, re-sign and transform jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be re-signed using the settings provided in `Re-sign algo`. You can also change the location of the token using `Token location`, remove fields using `Remove token fields`, set fields value using `Set token fields` and even rename fields using `Rename token fields`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also use a mini expression language in `Set token fields`. You just have to add expressions in values like `${expression}`. Supported expressions are the following :\n\n* `${date}` => set the current date\n* `${date.format('dd/MM/yyyy')}` => set the current date formatted with the format you want\n* `${token.fieldName}` => get the value of the field named `fieldName`\n* `${token.fieldName.replace('a', 'b')}` => get the value of the field named `fieldName` and replace `a` with `b`\n* `${token.fieldName.replaceAll('[0-9]', '-')}` => get the value of the field named `fieldName` and replace digits with `-`\n\nyou can of course use multiple expressions in one field like `my-value-is-${date}-with${token.user}`\n\n## Global verifications\n\nYou can create global jwt verifiers and reference them in your services (from the `Type` selector). When you set the type of verification to `Reference to a global definition`, you can choose an existing global jwt verifier\n\n@@@ div { .centered-img }\n\n@@@\n\nTo create a global verifier, go to `Settings (cog icon) / Global Jwt Verifiers` and it will display the list of global verifiers.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can them create, edit or delete verifiers\n\n@@@ div { .centered-img }\n\n@@@\n\n" + }, + { + "name": "monitoring.md", + "id": "/topics/monitoring.md", + "url": "/topics/monitoring.html", + "title": "Monitoring Otoroshi", + "content": "# Monitoring Otoroshi\n\nThe Otoroshi API exposes two endpoints for \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\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 (`app.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 `app.health.accessKey`, `otoroshi.metrics.accessKey` will have the value of `app.health.accessKey`.\n \n## Examples\n\nlet say `app.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": "mtls.md", + "id": "/topics/mtls.md", + "url": "/topics/mtls.html", + "title": "Mutual TLS with Otoroshi", + "content": "# Mutual TLS with Otoroshi\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```\nplay.server.https.wantClientAuth=true\n# or\n# play.server.https.wantClientNeed=true\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```\nHTTPS_WANT_CLIENT_AUTH=true \n# HTTPS_NEED_CLIENT_AUTH=true \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\n@@@ warning\nThe following section is under rewrite. The following content is deprecated\n@@@\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@@@ note { title=\"Experimental Feature\" }\nDynamic Mutual TLS is an experimental feature. It can change until it becomess an official feature\n@@@\n\n## End-to-end mTLS\n\nThe use case is the following :\n\n@@@ div { .centered-img }\n\n@@@\n\nfor this demo you will have to edit your `/etc/hosts` file to add the following entries\n\n```\n127.0.0.1 api.backend.lol api.frontend.lol www.backend.lol www.frontend.lol validation.backend.lol\n```\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.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.backend.lol.key -out ./server/_.backend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.backend.lol.key -sha256 -out ./server/_.backend.lol.csr -subj \"/CN=*.backend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.backend.lol.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.lol.cer\n# verify the certificate, should output './server/_.backend.lol.cer: OK'\nopenssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.lol.cer\n\n\n# now create the frontend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.frontend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.frontend.lol.key -out ./server/_.frontend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.frontend.lol.key -sha256 -out ./server/_.frontend.lol.csr -subj \"/CN=*.frontend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.frontend.lol.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.lol.cer\n# verify the certificate, should output './server/_.frontend.lol.cer: OK'\nopenssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.lol.cer\n\n\n# now create the client cert key for backend, use password as pass phrase\nopenssl genrsa -out ./client/_.backend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.backend.lol.key -out ./client/_.backend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.backend.lol.key -out ./client/_.backend.lol.csr -subj \"/CN=*.backend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.backend.lol.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.lol.cer\n# generate a pkcs12 version of the cert and key, use password as password\nopenssl pkcs12 -export -clcerts -in client/_.backend.lol.cer -inkey client/_.backend.lol.key -out client/_.backend.lol.p12\n\n\n# now create the client cert key for frontend, use password as pass phrase\nopenssl genrsa -out ./client/_.frontend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.frontend.lol.key -out ./client/_.frontend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.frontend.lol.key -out ./client/_.frontend.lol.csr -subj \"/CN=*.frontend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.frontend.lol.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.lol.cer\n# generate a pkcs12 version of the cert and key, use password as password\nopenssl pkcs12 -export -clcerts -in client/_.frontend.lol.cer -inkey client/_.frontend.lol.key -out client/_.frontend.lol.p12\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.lol.cer\n│   ├── _.backend.lol.csr\n│   ├── _.backend.lol.key\n│   ├── _.backend.lol.p12\n│   ├── _.frontend.lol.cer\n│   ├── _.frontend.lol.csr\n│   ├── _.frontend.lol.key\n│   └── _.frontend.lol.p12\n└── server\n ├── _.backend.lol.cer\n ├── _.backend.lol.csr\n ├── _.backend.lol.key\n ├── _.frontend.lol.cer\n ├── _.frontend.lol.csr\n └── _.frontend.lol.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.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n}; \n\nhttps.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```\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.lol:8444/\n# will print {\"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.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nhttps.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```\n\nyou can test your new server with\n\n```sh\ncurl --cacert ./ca/ca-backend.cer --cert-type pkcs12 --cert ./client/_.backend.lol.p12:password https://api.backend.lol:8444/\n# will print {\"message\":\"Hello World!\"}\n```\n\n### Otoroshi setup\n\nDownload the latest version of the Otoroshi jar and run it like\n\n```sh\njava -jar 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 / xxxxxxxxxxxx\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 / xxxxxxxxxxxx` displayed in the logs. Once logged in, create a new public service exposed on `http://api.frontend.lol` that targets `ahttps://api.backend.lol:8444/`.\n\n@@@ div { .centered-img }\n\n@@@\n\nand test it\n\n```sh\ncurl http://api.frontend.lol:8080/\n# the following error should be returned: {\"Otoroshi-Error\":\"Something went wrong, you should try later. Thanks for your understanding.\"}\n```\n\n@@@ warning\nAs seen before, the target of the otoroshi service is `ahttps://api.backend.lol:8444/`. `ahttps://` is not a typo and is intended. This tells otoroshi to use its experimental `http client` with dynamic tls support to fetch this resource.\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.lol` 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.lol.cer` and `./client/_.backend.lol.key` respectively in `Certificate full chain` and `Certificate private key`.\n\n@@@ div { .centered-img }\n\n@@@\n\nand retry the following curl command \n\n```sh\ncurl http://api.frontend.lol:8080/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\nnow we have to expose `https://api.frontend.lol: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.lol.cer` and `./server/_.frontend.lol.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nand try the following command\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer https://api.frontend.lol:8443/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\nnow we have to enforce the fact that we want client certificate for `api.frontend.lol`. To do that, we have to create a `Validation authority` in otoroshi and use it on the `api.frontend.lol` service. Go to http://otoroshi.oto.tools:8080/bo/dashboard/validation-authorities and create a new item. A validation authority is supposed to be a remote service that will say if the client certificate is valid. Here we don't really care if the certificate is valid or not, but we want to enforce the fact that there is a client certificate. So just check the `All cert. valid button`.\n\n@@@ div { .centered-img }\n\n@@@\n\nnow go back on your `api.frontend.lol` service, in the `Validation authority` section and select the authority you just created.\n\n@@@ div { .centered-img }\n\n@@@\n\nnow if you retry \n\n```sh\ncurl --cacert ./ca/ca-frontend.cer https://api.frontend.lol:8443/\n# the output should be: {\"Otoroshi-Error\":\"You're not authorized here !\"}\n```\n\nyou should get an error because no client cert. is passed with the request. But if you pass the `./client/_.frontend.lol.p12` client cert in your curl call\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/_.frontend.lol.p12:password https://api.frontend.lol:8443/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\n### End to end test\n\nNow we can try to write a small nodejs client that uses our client certificates. Create a `client.js` file with the following code\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nprocess.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;\n\nconst options = { \n hostname: 'api.frontend.lol', \n port: 8443, \n path: '/', \n method: 'GET', \n key: fs.readFileSync('./client/_.frontend.lol.key'), \n cert: fs.readFileSync('./client/_.frontend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-frontend.cer'), \n}; \n\nconst req = https.request(options, (res) => { \n console.log('statusCode', res.statusCode);\n console.log('headers', res.headers);\n console.log('body:');\n res.on('data', (data) => { \n process.stdout.write(data); \n }); \n}); \n\nreq.end(); \n\nreq.on('error', (e) => { \n console.error(e); \n});\n```\n\nand run the following command\n\n```sh\n$ node client.js\n# statusCode 200\n# headers { date: 'Mon, 10 Dec 2018 16:01:11 GMT',\n# connection: 'close',\n# 'transfer-encoding': 'chunked',\n# 'content-type': 'application/json' }\n# body:\n# {\"message\":\"Hello World!\"}\n```\n\nAnd that's it \n\n## Validating client certificates based on user identity\n\n@@@ note { title=\"Experimental Feature\" }\nValidation authorities is an experimental feature. It can change until it becomess an official feature\n@@@\n\nThe use case is the following :\n\n@@@ div { .centered-img }\n\n@@@\n\nthe idea here is to provide a unique client certificate per device that can access Otoroshi and use a validation authority to check if the user is allowed to access the underlying app with a specific device.\n\n### Generate client certificates for devices\n\nTo do that we are going to create two client certificates, one per device (let say for a laptop and a desktop computer). We are going to use the device serial number as common name of the certificate to be able to identify the device behind the certificate.\n\n```sh\nopenssl genrsa -out ./client/device-1.key 2048\nopenssl rsa -in ./client/device-1.key -out ./client/device-1.key\nopenssl req -new -key ./client/device-1.key -out ./client/device-1.csr -subj \"/CN=mbp-123456789\"\nopenssl x509 -req -days 365 -sha256 -in ./client/device-1.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 3 -out ./client/device-1\nopenssl pkcs12 -export -clcerts -in client/device-1 -inkey client/device-1.key -out client/device-1.p12\n\nopenssl genrsa -out ./client/device-2.key 2048\nopenssl rsa -in ./client/device-2.key -out ./client/device-2.key\nopenssl req -new -key ./client/device-2.key -out ./client/device-2.csr -subj \"/CN=nuc-987654321\"\nopenssl x509 -req -days 365 -sha256 -in ./client/device-2.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 4 -out ./client/device-2\nopenssl pkcs12 -export -clcerts -in client/device-2 -inkey client/device-2.key -out client/device-2.p12\n```\n\n### Setup actual validation\n\nnow we are going to write an validation authority (with mTLS too) that is going to respond on `https://validation.backend.lol:8445`. The server has access to a list of apps, users and devices to check if everything is correct. In this implementation, the lists are hardcoded, but you can write your own implementation that will fetch data from your corporate LDAP, CA, etc. Create a `validation.js` file and add the following content. Don't forget to do `yarn add x509` before running the server with `node validation.js`\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \nconst x509 = require('x509');\n\n// list of knwon apps\nconst apps = [\n {\n \"id\": \"iogOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"name\": \"my-web-service\",\n \"description\": \"A service that says hello\",\n \"host\": \"www.frontend.lol\"\n }\n];\n\n// list of known users\nconst users = [\n {\n \"name\": \"Mathieu\",\n \"email\": \"mathieu@oto.tools\",\n \"appRights\": [\n {\n \"id\": \"iogOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"profile\": \"user\",\n \"forbidden\": false\n },\n {\n \"id\": \"PqgOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"profile\": \"none\",\n \"forbidden\": true\n },\n ],\n \"ownedDevices\": [\n \"mbp-123456789\",\n \"nuc-987654321\",\n ]\n }\n];\n\n// list of known devices\nconst devices = [\n {\n \"serialNumber\": \"mbp-123456789\",\n \"hardware\": \"Macbook Pro 2018 13 inc. with TouchBar, 2.6 GHz, 16 Gb\",\n \"acquiredAt\": \"2018-10-01\",\n },\n {\n \"serialNumber\": \"nuc-987654321\",\n \"hardware\": \"Intel NUC i7 3.0 GHz, 32 Gb\",\n \"acquiredAt\": \"2018-09-01\",\n },\n {\n \"serialNumber\": \"iphone-1234\",\n \"hardware\": \"Iphone XS, 256 Gb\",\n \"acquiredAt\": \"2018-12-01\",\n }\n];\n\nconst options = { \n key: fs.readFileSync('./server/_.backend.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nfunction readBody(request) {\n return new Promise((success, failure) => {\n const body = [];\n request.on('data', (chunk) => {\n body.push(chunk);\n }).on('end', () => {\n const bodyStr = Buffer.concat(body).toString();\n success(JSON.parse(bodyStr));\n });\n });\n}\n\nfunction chainIsValid(chain) {\n // validate cert dates\n // validate cert against clr\n // validate whatever you want here\n return true;\n}\n\nfunction call(req, res) {\n readBody(req).then(body => {\n const service = body.service;\n const email = (body.user || { email: 'mathieu@oto.tools' }).email; // here, should not be null if used with an otoroshi auth. module\n // common name should be device serial number\n const commonName = x509.getSubject(body.chain).commonName\n // search for a known device\n const device = devices.filter(d => d.serialNumber === commonName)[0];\n // search for a known user\n const user = users.filter(d => d.email === email)[0];\n // search for a known application\n const app = apps.filter(d => d.id === service.id)[0];\n res.writeHead(200, { 'Content-Type': 'application/json' }); \n if (chainIsValid(body.chain.map(x509.parseCert)) && user && device && app) {\n // check if the user actually owns the device\n const userOwnsDevice = user.ownedDevices.filter(d => d === device.serialNumber)[0];\n // check if the user has rights to access the app\n const rights = user.appRights.filter(d => d.id === app.id)[0];\n const hasRightToUseApp = !rights.forbidden\n if (userOwnsDevice && hasRightToUseApp) {\n // yeah !!!!\n console.log(`Call from user \"${user.email}\" with device \"${device.hardware}\" on app \"${app.name}\" with profile \"${rights.profile}\" authorized`)\n res.end(JSON.stringify({ status: 'good', profile: rights.profile }) + \"\\n\"); \n } else {\n // nope !!! nope, nope nope\n console.log(`Call from user \"${user.email}\" with device \"${device.hardware}\" on app \"${app.name}\" unauthorized because user doesn't owns the hardware or has no rights`)\n res.end(JSON.stringify({ status: 'unauthorized' }) + \"\\n\"); \n }\n } else {\n console.log(`Call unauthorized`)\n res.end(JSON.stringify({ status: 'unauthorized' }) + \"\\n\"); \n }\n });\n}\n\nhttps.createServer(options, call).listen(8445);\n```\n\nthe corresponding authority validation can be created in Otoroshi like \n\n```json\n{\n \"id\": \"r7m8j31rh66hhdia3ormfm0wfevu1kvg0zgaxsp3oxb6ivf7fy8kvygmvnrlxv81\",\n \"name\": \"Actual validation authority\",\n \"description\": \"Actual validation authority\",\n \"url\": \"ahttps://validation.backend.lol:8445\",\n \"host\": \"validation.backend.lol\",\n \"goodTtl\": 600000,\n \"badTtl\": 60000,\n \"method\": \"POST\",\n \"path\": \"/certificates/_validate\",\n \"timeout\": 10000,\n \"noCache\": false,\n \"alwaysValid\": false,\n \"headers\": {}\n}\n```\n\nbut you don't need to create it right now.\n\nTypically, a validation authority server is a server with a route on `POST /certificates/_validate` that accepts `application/json` and returns `application/json` with a body like\n\n```json\n{\n \"apikey\": nullable {\n \"clientId\": String,\n \"clientName\": String,\n \"authorizedEntities\": Seq[String],\n \"enabled\": Boolean,\n \"readOnly\": Boolean,\n \"allowClientIdOnly\": Boolean,\n \"throttlingQuota\": Long,\n \"dailyQuota\": Long,\n \"monthlyQuota\": Long,\n \"metadata\": Map[String, String]\n },\n \"user\": nullable {\n \"email\": String,\n \"name\": String,\n },\n \"service\": {\n \"id\": String,\n \"name\": String,\n \"groups\": Seq[String],\n \"domain\": String,\n \"env\": String,\n \"subdomain\": String,\n \"root\": String,\n \"metadata\": String\n },\n \"chain\": PemFormattedCertificateChainString,\n \"fingerprints\": Array[String]\n}\n```\n\n\n### Setup Otoroshi\n\nYou can start Otoroshi and import data from the `state.json` file in the demo folder. The login tuple is `admin@otoroshi.io / password`. The `state.json` file contains everything you need for the demo, like certificates, service descriptors, auth. modules, etc ...\n\n```sh\njava -Dapp.importFrom=$(pwd)/state.json -Dapp.privateapps.port=8080 -jar 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 - Importing from: /pwd/state.json\n[info] play.api.Play - Application started (Prod)\n[info] otoroshi-env - Successful import !\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```\n\n### Testing \n\nYou can test the service with curl like\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/device-1.p12:password https://www.frontend.lol:8443/\n# output:

Hello World !!!

\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/device-2.p12:password https://www.frontend.lol:8443/\n# output:

Hello World !!!

\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/_.frontend.lol.p12:password https://www.frontend.lol:8443/\n# output: {\"Otoroshi-Error\":\"You're not authorized here !\"}\n```\n\nas expected, the first two call works as their common name is known by the validation server. The last one fails as it's not known.\n\n### Validate user identity\n\nNow let's try to setup firefox to provide the client certificate. Open firefox settings, go to `privacy settings and security` and click on `display certificates` at the bottom of the page. Here you can add the frontend CA (`./ca/ca-frontend.cer`) in the `Authorities` tab, check the 'authorize this CA to identify websites', and then in the `certificates` tab, import one of the devices `.p12` file (like `./client/device-1.p12`). Firefox will ask for the files password (it should be `password`).\n\n@@@ div { .centered-img }\n\n@@@\n\nNow restart firefox.\n\nNext, go to the `my-web-service` service in otoroshi (log in with `admin@otoroshi.io / password`) and activate `Enforce user login` in the Authentication section. It means that now, you'll have to log in when you'll go to https://www.frontend.lol:8443. With authentication activated on otoroshi, the user identity will be sent to the validation authority, so you can change the following line in the file `validation.js`\n\n```js\nconst email = (body.user || { email: 'mathieu@oto.tools' }).email; // here, should not be null if used with an otoroshi auth. module\n```\n\nto\n\n```js\nconst email = body.user.email;\n```\n\nThen, in Firefox, go to https://www.frontend.lol:8443/, firefox will ask which client certificate to use. Select the one you imported (in the process, maybe firefox will warn you that the certificate of the site is auto signed, just ignore it and continue ;) )\n\n@@@ div { .centered-img }\n\n@@@\n\nthen, you'll see a login screen from otoroshi. You can log in with `mathieu@oto.tools / password` and then you should see the hello world message.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Going further with user authentication\n\nFor stronger user authentication, you can try to use an auth. module baked by a keycloak instance with yubikey as a strong second factor authentication instead of the basic auth. module we used previously in this article.\n" + }, + { + "name": "plugins.md", + "id": "/topics/plugins.md", + "url": "/topics/plugins.html", + "title": "Otoroshi plugins", + "content": "# Otoroshi 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\n\n* `request sinks` plugins: used when no services are matched in otoroshi. Can reply with any content\n* `pre-routes` plugins: used to extract values (like custom apikeys) and provide them to other plugins or otoroshi engine\n* `access validation` plugins: used to validate if a request can pass or not based on whatever you want\n* `request transformer` plugins: used to transform request, responses and their body. Can be used to return arbitrary content\n* `event listener` plugins: any plugin type can listen to otoroshi internal events and react to thems\n* `job` plugins: tasks taht can run automatically once, on be scheduled with a cron expression or every defined interval\n\n## Code and signatures\n\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/requestsink.scala#L11-L16\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/routing.scala#L60-L63\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/accessvalidator.scala#L63-L82\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/script.scala#L314-L455\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#L74-L81\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.6.x/api/scala/index.html#package\n* https://www.playframework.com/documentation/2.6.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\nA lot of plugins comes with otoroshi, you can find it 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" + }, + { + "name": "snow-monkey.md", + "id": "/topics/snow-monkey.md", + "url": "/topics/snow-monkey.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": "ssl.md", + "id": "/topics/ssl.md", + "url": "/topics/ssl.html", + "title": "SSL/TLS termination with Otoroshi", + "content": "# SSL/TLS termination with Otoroshi\n\nOtoroshi can be used as an SSL/TLS termination. It is enabled by default but you can customise HTTPS port with `https.port` config. and env. var `HTTPS_PORT`. You can create upload any certificate you want in the Otoroshi UI or using the API. Just go to `settings (cog icon) / SSL/TLSS certificates`.\n\n@@@ note { title=\"Experimental Feature\" }\nDynamic SSL/TLS termination is an experimental feature. It can change until it becomess an official feature\n@@@\n\n@@@ note { title=\"TLS 1.3 support\" }\nOtoroshi does support TLS 1.3 when used in combination with JDK 11\n\n\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\nHere 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 with no password on the private key.\n\nYou can remove the password of a key with the following command\n\n```sh\nopenssl rsa -in keywithpassword.key -out keywithoutpassword.key\n```\n\n@@@ div { .centered-img }\n\n@@@\n\n" + }, + { + "name": "1-groups.md", + "id": "/usage/1-groups.md", + "url": "/usage/1-groups.html", + "title": "Managing service groups", + "content": "# Managing service groups\n\nGo to `settings (cog icon) / All service groups` to access the list of service groups.\n\n@@@ div { .centered-img }\n\n@@@\n\nAnd you should see the list of existing `Service groups`.\n\n@@@ div { .centered-img }\n\n@@@\n\nBut what is a `Service group` anyway ?\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi :\n\n* **service groups**\n* service descriptors\n* api keys\n\n@@@ div { .centered-img }\n\n@@@\n\nA `service group` is just some kind of logical container for `service descriptors`. A `service group` also has some `api keys` assigned that will be used to access all the `service descriptors` contained in the `service group`.\n\n## Create a service group\n\nA `service group` is a really simple structure with an `id`, a name and a description. To create a new one, just click on the `Add item` button.\n\n@@@ div { .centered-img }\n\n@@@\n\nmodify the name and the description of the group\n\n@@@ div { .centered-img }\n\n@@@\n\nand click on `Create group`\n\n@@@ div { .centered-img }\n\n@@@\n\nThen, you should find your brand new `Service group` in the list of `Service groups`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Update a service\n\nTo update a `Service group`, just click on the edit button of your `Service group`\n\n@@@ div { .centered-img }\n\n@@@\n\nUpdate the name and description of the `Service group` and click on the `Update group` button to validate name update.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Delete a service group\n\nTo delete a `Service group`, just click on the delete button of your `Service group`\n\n@@@ div { .centered-img }\n\n@@@\n\nFinally confirm the command\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "2-services.md", + "id": "/usage/2-services.md", + "url": "/usage/2-services.html", + "title": "Managing services", + "content": "# Managing services\n\nNow let's create services. 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.\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi\n\n* service groups\n* **service descriptors**\n* api keys\n\n@@@ div { .centered-img }\n\n@@@\n\nA `service descriptor` is contained in one or multiple `service group`s and is allowed to be accessed by all the `api key`s authorized on those `service group`s or apikeys directly authorized on the service itself.\n\n## Create a service descriptor\n\nTo create a `service descriptor`, click on `Add service` on the Otoroshi sidebar. Then you will be asked to choose a name for the service and the group of the service. You also have two buttons to create a new group and assign it to the service and create a new group with a name based on the service name.\n\nYou will have a serie of toggle buttons to\n\n* activate / deactivate a service\n* display maintenance page for a service\n* display contruction page for a service\n* enable otoroshi custom response headers containing request id, latency, etc \n* force https usage on the exposed service\n* enable read only flag : this service will only be used with `HEAD`, `OPTIONS` and `GET` http verbs. You can also active the same flag on `ApiKey`s to be more specific on who cannot use write http verbs.\n\nThen, you will be able to choose the URL that will be used to reach your new service on Otoroshi.\n\n@@@ div { .centered-img #service-flags }\n\n@@@\n\nIn the `service targets` section, you will be able to choose where the call will be forwarded. You can use multiple targets, in that case, Otoroshi will perform a round robin load balancing between the targets. If the `override Host header` toggle is on, the host header will be changed for the host of the target. For example, if you request `http://www.oto.tools/api` with a target to `http://www-internal.service.local/api`, the target will receive a `Host: www-internal.service.local` instead of `Host: www.oto.tools`.\n\nYou can also specify a target root, if you say that the target root is `/foo/`, then any call to `https://my.api.foo` will call `http://192.168.0.42/foo/` and nay call to `https://my.api.foo/bar` will call `http://192.168.0.42/foo/bar`.\n\nIn the URL patterns section, you will be able to choose, URL by URL which is private and which is public. By default, all services are private and each call must provide an `api key`. But sometimes, you need to access a service publicly. In that case, you can provide patterns (regex) to make some or all URL public (for example with the pattern `/.*`). You also have a `private pattern` field to restrict public patterns.\n\n@@@ div { .centered-img #targets }\n\n@@@\n\n### Otoroshi exchange protocol\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 `app.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\n\n### Canary mode\n\nOtoroshi provides a feature called `Canary mode`. It lets you define new targets for a service, and route a percentage of the traffic on those targets. It's a good way to test a new version of a service before public release. As any client need to be routed to the same version of targets any time, Otoroshi will issue a special header and a cookie containing a `session id`. The header is named `Otoroshi-Canary-Id`.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service health check\n\nOtoroshi is also capable of checking the health of a service. You can define a URL that will be tested, and Otoroshi will ping that URL regularly. Will doing so, Otoroshi will pass a numeric value in a header named `Otoroshi-Health-Check-Logic-Test`. You can respond with a header named `Otoroshi-Health-Check-Logic-Test-Result` that contains the value of `Otoroshi-Health-Check-Logic-Test` + 42 to indicate that the service is working properly.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service circuit breaker\n\nIn Otoroshi, each service has its own client settings with a circuit breaker and some retry capabilities. In the `Client settings` section, you will be able to customize the client's behavior.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service settings\n\nYou can also provide some additionnal information about a given service, like an `Open API` descriptor, some metadata, a list of whitelisted/blacklisted ip addresses, etc.\n\n@@@ div { .centered-img #service-meta }\n\n@@@\n\n### HTTP Headers\n\nHere you can define some headers that will be added to each request to client requests or responses. \nYou will also be able to define headers to route the call only if the defined header is present on the request.\n\n@@@ div { .centered-img #service-meta }\n\n@@@\n\n### CORS \n\nIf you enabled this section, CORS will be automatically supported on the current service provider. The pre-flight request will be handled by Otoroshi. You can customize every CORS headers :\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service authentication\n\nSee @ref:[Aauthentication](./9-auth.md)\n\n### Custom error templates\n\nFinally, you can define custom error templates that will be displayed when an error occurs when Otoroshi try to reach the target or when Otoroshi itself has an error. You can also define custom templates for maintenance and service pages.\n" + }, + { + "name": "3-apikeys.md", + "id": "/usage/3-apikeys.md", + "url": "/usage/3-apikeys.html", + "title": "Managing API keys", + "content": "# Managing API keys\n\nNow that you know how to create service groups and service descriptors, we will see how to create API keys.\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi.\n\n* service groups\n* service descriptors\n* **api keys**\n\n@@@ div { .centered-img }\n\n@@@\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 group`s/`service descriptor`s.\n\nIn the Otoroshi admin dashboard, we chose to access `API keys` from `service descriptors` only, but when you access `API keys` for a `service descriptor`, you actually access `API keys` for the `service group` containing the `service descriptor`.\n\n`API keys` can be provided to Otoroshi through :\n\n* `Otoroshi-Authorization: Basic $base64(client_id:client_secret)` header, in that case, the `Otoroshi-Authorization` header will **not** be sent to the target. `Basic ` is optional.\n* `Authorization: Basic $base64(client_id:client_secret)` header, in that case, the `Authorization` header **will** be sent to the target\n* `Otoroshi-Token: Bearer $jwt_token` where the JWT token has been signed with the `API key` client secret, in that case, the `Otoroshi-Token` header will **not** be sent to the target. `Bearer ` is optional.\n* `Authorization: Bearer $jwt_token` where the JWT token has been signed with the `API key` client secret, in that case, the `Authorization` header **will** be sent to the target\n* `Cookie: access_token=$jwt_token;` where the JWT token has been signed with the `API key` client secret, in that case, the cookie named `access_token` **will** be sent to the target\n* `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers, in that case the `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers will not be sent to the target.\n\n## List API keys for a service descriptor\n\nGo to a service descriptor using `All services` quick link in the sidebar or the search box.\n\n@@@ div { .centered-img }\n\n@@@\n\nSelect a `service descriptor`.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `API keys` in the sidebar\n\n@@@ div { .centered-img }\n\n@@@\n\nYou should see the list of API keys for that `service descriptor`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Create an API key for a service descriptor\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can add a name for your new API key, you can also change client's id and client's secret. You can also configure the throttling rate of the API key (calls per second), and the authorized number of call per day and per month. You may also activate or de-activate the api key from that screen.\n\nInformations about current quotas usage will be returned in response headers.\n\n* `Otoroshi-Daily-Calls-Remaining` : authorized calls remaining for this day\n* `Otoroshi-Monthly-Calls-Remaining` : authorized calls remaining for this month\n* `Otoroshi-Proxy-Latency` : latency induced by Otoroshi\n* `Otoroshi-Upstream-Latency` : latency between Otoroshi and target\n\n@@@ div { .centered-img #quotas }\n\n@@@\n\n@@@ warning\nDaily and monthly quotas are based on the following rules :\n\n* daily quota is computed between 00h00:00.000 and 23h59:59.999\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## Update an API key\n\nTo update an `API key`, just click on the edit button of your `API key`\n\n@@@ div { .centered-img }\n\n@@@\n\nUpdate the name, secret, state and quotas (if needed) of the `API key` and click on the `Update API key` button\n\n@@@ div { .centered-img }\n\n@@@\n\n## Delete an API key\n\nTo delete an `API key`, just click on the delete button of your `API key`\n\n@@@ div { .centered-img }\n\n@@@\n\nand confirm the command\n\n@@@ div { .centered-img }\n\n@@@\n\n### Read only\n\nThe read only flag on an `ApiKey` this apikey can only use allowed services with `HEAD`, `OPTIONS` and `GET` http verbs.\n\n## Use a JWT token to pass an API key\n\nYou can use a JWT token to pass an API key to Otoroshi. \nYou can use `Otoroshi-Authorization: Bearer $jwt_token`, `Authorization: Bearer $jwt_token` header and `Cookie: access_token=$jwt_token;` to pass the JWT token.\nYou have to create a JWT token with a signing algorythm that can be `HS256` or `HS512`. Then you have to provide an `iss` claim with the value of your API key `clientId` and sign the JWT token with your API key `clientSecret`.\n\nFor example, with an API key like `clientId=abcdef` and `clientSecret=1234456789`, your JWT token should look like\n\n```json\n{\n \"alg\": \"HS256\",\n \"typ\": \"JWT\"\n}\n{\n \"iss\":\"abcdef\",\n \"name\": \"John Doe\",\n \"admin\": true\n}\n```\n\nin that case, when you sign the token with the secret of the API key `1234456789`, the signature will be `_eancnYCD3makSSox2v2xErjNYkRtcX558QiJGCbino`, resulting in a encoded JWT header like\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJpc3MiOiJhYmNkZWYiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.\n_eancnYCD3makSSox2v2xErjNYkRtcX558QiJGCbino\n```\n" + }, + { + "name": "4-monitor.md", + "id": "/usage/4-monitor.md", + "url": "/usage/4-monitor.html", + "title": "Monitoring services", + "content": "# Monitoring services\n\nOnce you have declared services, you can monitor them with Otoroshi.\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi\n@@@\n\nOnce you have setup @ref:[Otoroshi events push to an elastic cluster](../integrations/analytics.md) (through webhooks, kafka, or elastic integration) you can setup Otoroshi events read from an elastic cluster. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (write)` 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" + }, + { + "name": "5-sessions.md", + "id": "/usage/5-sessions.md", + "url": "/usage/5-sessions.html", + "title": "Managing sessions", + "content": "# Managing sessions\n\nWith Otoroshi you can manage sessions of connected users and you can discard sessions whenever you want. Session last 24h by default and you can customize them with `app.backoffice.session.exp` and `app.privateapps.session.exp` @ref:[config keys](../firstrun/configfile.md)\n\n## Admin. sessions\n\nTo see last current admin session on Otoroshi from the UI, go to `settings (cog icon) / Admins sessions`. Here you can discard individual sessions or all sessions at once using `Discard session` and `Discard all sessions` buttons.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Private apps. session\n\nTo see last current admin session on Otoroshi from the UI, go to `settings (cog icon) / Priv. apps sessions`. Here you can discard individual sessions or all sessions at once using `Discard session` and `Discard all sessions` buttons.\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "6-audit.md", + "id": "/usage/6-audit.md", + "url": "/usage/6-audit.html", + "title": "Auditing Otoroshi", + "content": "# Auditing Otoroshi\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 `app.events.maxSize` @ref:[config key](../firstrun/configfile.md)). 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\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi. See @ref:[Elastic setup section](../integrations/analytics.md)\n@@@\n\n## Audit trail\n\nTo see last `app.events.maxSize` admin actions on Otoroshi from the UI, go to `settings (cog icon) / Audit log`.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Alerts\n\nTo see last `app.events.maxSize` alerts on Otoroshi from the UI, go to `settings (cog icon) / Alerts log`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also have a look at the payload sent to the Otoroshi server by clicking the `content` button\n\n@@@ div { .centered-img }\n\n@@@\n\n## List of possible alerts\n\n```\nMaxConcurrentRequestReachedAlert\nCircuitBreakerOpenedAlert\nCircuitBreakerClosedAlert\nSessionDiscardedAlert\nSessionsDiscardedAlert\nPanicModeAlert\nOtoroshiExportAlert\nU2FAdminDeletedAlert\nBlackListedBackOfficeUserAlert\nAdminLoggedInAlert\nAdminFirstLogin\nAdminLoggedOutAlert\nDbResetAlert\nDangerZoneAccessAlert\nGlobalConfigModification\nRevokedApiKeyUsageAlert\nServiceGroupCreatedAlert\nServiceGroupUpdatedAlert\nServiceGroupDeletedAlert\nServiceCreatedAlert\nServiceUpdatedAlert\nServiceDeletedAlert\nApiKeyCreatedAlert\nApiKeyUpdatedAlert\nApiKeyDeletedAlert\n```\n" + }, + { + "name": "7-metrics.md", + "id": "/usage/7-metrics.md", + "url": "/usage/7-metrics.html", + "title": "Otoroshi global metrics", + "content": "# Otoroshi global metrics\n\nOtoroshi provide some global metrics about services usage. Go to `settings (cog icon) / Global Ananlytics`\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi. See @ref:[Elastic setup section](../integrations/analytics.md)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "8-importsexports.md", + "id": "/usage/8-importsexports.md", + "url": "/usage/8-importsexports.html", + "title": "Import and export", + "content": "# Import and export\n\nWith Otoroshi you can easily save the current state of the proxy and restore it later. Go to `settings (cog icon) / Danger Zone` and scroll to the bottom of the page\n\n## Full export\n\nClick on the `Full export` button.\n\n@@@ div { .centered-img }\n\n@@@\n\nYour browser will start to download a JSON file containing the internal state of your Otoroshi cluster.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Full import\n\nIf you want to restore an export, go to `settings (cog icon) / Danger Zone` and scroll to the bottom of the page. Click on the `Recover from full export file` button\n\n@@@ div { .centered-img }\n\n@@@\n\nChoose export file on your system.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on the `Flush datastore and import ...` button, confirm and you will be logged out.\n\n@@@ div { .centered-img }\n\n@@@\n" + }, + { + "name": "9-auth.md", + "id": "/usage/9-auth.md", + "url": "/usage/9-auth.html", + "title": "Authentication", + "content": "# Authentication\n\nYou can create auth. configuration in Otoroshi. Just go to `settings (cog icon) / Authentication configs`.\n\n## OAuth 2\n\nCreate a new `Generic oauth2 provider` config and customize the following informations:\n\n```json\n{\n \"clientId\": \"xxxx\",\n \"clientSecret\": \"xxxx\",\n \"authorizeUrl\": \"http://yourOAuthServer/oauth/authorize\",\n \"tokenUrl\": \"http://yourOAuthServer/oauth/token\",\n \"userInfoUrl\": \"http://yourOAuthServer/userinfo\",\n \"loginUrl\": \"http://yourOAuthServer/login\",\n \"logoutUrl\": \"http://yourOAuthServer/logout?redirectQueryParamName=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\nIf used for BackOffice authentication, the callback url should be `http://otoroshi.oto.tools/backoffice/auth0/callback`.\n\nFor `logoutUrl`, `redirectQueryParamName` is a parameter with a name specific to your OAuth2 provider (for example, in Auth0, this parameter is called `returnTo`, in Kecloak it is called `redirect_uri`).\n\nif you are using a [KeyCloak](https://www.keycloak.org/) server, you can configure it this way, assuming you are using the master realm and you created a new client with a client secret, callback urls set to `http://privateapps.oto.tools/*`.\n\n```json\n{\n \"clientId\": \"clientId\",\n \"clientSecret\": \"clientSecret\",\n \"authorizeUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/auth\",\n \"tokenUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/token\",\n \"userInfoUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/userinfo\",\n \"loginUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/auth\",\n \"logoutUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/logout?redirect_uri=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\n## Ldap\n\nCreate a new `Ldap auth. provider` config and customize the following informations:\n\n```json\n{\n \"serverUrl\": \"ldap://ldap.forumsys.com:389\",\n \"searchBase\": \"dc=example,dc=com\",\n \"groupFilter\": \"ou=chemists\",\n \"searchFilter\": \"(mail=${username})\",\n \"adminUsername\": \"cn=read-only-admin,dc=example,dc=com\",\n \"adminPassword\": \"password\",\n \"nameField\": \"cn\",\n \"emailField\": \"mail\"\n}\n```\n\n## In Memory\n\nCreate a new `In memory auth. provider` config and then you will be able to create new users. To set the password, just click on the `Set password` button. It will generate a BCrypt hash of the password you typed.\n\n## Auth0\n\nCreate a new OAuth 2 config and add the following informations:\n\n```json\n{\n \"clientId\": \"yourAuth0ClientId\",\n \"clientSecret\": \"yourAuth0ClientSecret\",\n \"authorizeUrl\": \"https://yourAuth0Domain/authorize\",\n \"tokenUrl\": \"https://yourAuth0Domain/oauth/token\",\n \"userInfoUrl\": \"https://yourAuth0Domain/userinfo\",\n \"loginUrl\": \"https://yourAuth0Domain/authorize\",\n \"logoutUrl\": \"https://yourAuth0Domain/v2/logout?returnTo=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"otoroshiDataField\": \"app_metadata | otoroshi_data\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\nIf you enable Otoroshi exchange protocol, the JWT xill have the following fields (all optional)\n\n* `email`\n* `name`\n* `picture`\n* `user_id`\n* `given_name`\n* `family_name`\n* `gender`\n* `locale`\n* `nickname`\n\nIn Auth0, the metadata is a flat object placed in the `profile / http://yourdomain/app_metadata / otoroshi_data`. You might need to write an Auth0 rule to copy app metadata under `http://yourdomain/app_metadata`, the `http://yourdomain/app_metadata` value is a config property `app.appMeta`. The rule could be something like the following\n\n```js\nfunction (user, context, callback) {\n var namespace = 'http://yourdomain/';\n context.idToken[namespace + 'user_id'] = user.user_id;\n context.idToken[namespace + 'user_metadata'] = user.user_metadata;\n context.idToken[namespace + 'app_metadata'] = user.app_metadata;\n callback(null, user, context);\n}\n```" + }, + { + "name": "index.md", + "id": "/usage/index.md", + "url": "/usage/index.html", + "title": "Using Otoroshi", + "content": "# Using Otoroshi\n\nNow we will see how to use Otoroshi for basic tasks that will be useful for your day to day work with Otoroshi.\n\n@@@ index\n\n* [create group](./1-groups.md)\n* [create service](./2-services.md)\n* [create API Keys](./3-apikeys.md)\n* [monitor service](./4-monitor.md)\n* [sessions management](./5-sessions.md)\n* [Audit trail and alerts](./6-audit.md)\n* [Global metrics](./7-metrics.md)\n* [Exports and imports](./8-importsexports.md)\n* [Authentication](./9-auth.md)\n\n@@@\n" + } +] \ No newline at end of file diff --git a/docs/manual/content.json b/docs/manual/content.json new file mode 100644 index 0000000000..e8cd9519a8 --- /dev/null +++ b/docs/manual/content.json @@ -0,0 +1 @@ +[{"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 MAIF. Naturally we turned to PaaS solutions and chose the excellent Clever-Cloud 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 Service Mesh Pattern but the deployement model of Clever-Cloud 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 Clever-Cloud 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 MAIF like Izanami 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\nOtoroshi also provides some connectors that uses the Otoroshi admin API to automate Otorshi's instances when used with stuff like containers orchestrators. For more informations about that, just go to the @ref:[third party integrations chapter](./integrations/index.md)\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":"archi.md","id":"/archi.md","url":"/archi.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 [React](https://reactjs.org/) 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-beanstalk.md","id":"/deploy/aws-beanstalk.md","url":"/deploy/aws-beanstalk.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](../getotoroshi/fromdocker.md) 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](../firstrun/run.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](../getotoroshi/fromdocker.md), build a zip, and do all the Otoroshi custom configuration using ENVs.\n\nOr you download the @ref:[otoroshi.jar](../getotoroshi/frombinaries.md), 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:8\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 downstream 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 `app.storage=redis`, `app.redis.host` and `app.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":"clevercloud.md","id":"/deploy/clevercloud.md","url":"/deploy/clevercloud.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](../firstrun/env.md), 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":"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\n@@@ index\n\n* [Kubernetes](./kubernetes.md)\n* [Clever Cloud](./clevercloud.md)\n* [AWS - Elastic Beanstalk](./aws-beanstalk.md)\n* [others](./other.md) \n* [Scaling](./scaling.md) \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.0-rc.2\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.0-rc.2-jdk11\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":"other.md","id":"/deploy/other.md","url":"/deploy/other.html","title":"Others","content":"# Others\n\nOtoroshi can run wherever you want, even on a raspberry pi (Cluster^^) ;)\n\nThis section is not finished yet. So, as Otoroshi is available as a @ref:[Docker image](../getotoroshi/fromdocker.md) that you can run on any Docker compatible cloud, just go ahead and use it on cloud provider until we have more detailed documentation.\n\n## Running Otoroshi on AWS Elastic Beanstalk\n\nSee the @ref:[dedicated page to run Otoroshi on AWS Elastic Beanstalk](./aws-beanstalk.md)\n\n## Running Otoroshi on Amazon Elastic Container Service\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html)\n\n## Running Otoroshi on GCE\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Google Compute Engine container integration](https://cloud.google.com/compute/docs/containers/deploying-containers)\n\n## Running Otoroshi on Azure\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Azure Container Service](https://azure.microsoft.com/en-us/services/container-service/)\n\n## Running Otoroshi on Heroku\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Docker integration](https://devcenter.heroku.com/articles/container-registry-and-runtime)\n\n## Running Otoroshi on CloudFoundry\n\nDeploy the @ref:[Docker image](../firstrun/run.md#from-docker) using [Docker integration](https://docs.cloudfoundry.org/adminguide/docker.html)\n\n## Running Otoroshi on your own infrastructure\n\nAs Otoroshi is a [Play Framework](https://www.playframework.com) application, you can read the doc about putting a `Play` app in production.\n\nhttps://www.playframework.com/documentation/2.6.x/ProductionConfiguration\n\nDownload the latest @ref:[Otoroshi distribution](../getotoroshi/frombinaries.md), unzip it, customize it and run it.\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](../topics/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 -Dapp.storage=file -Dapp.liveJs=true -Dhttps.port=9998 -D-Dapp.privateapps.port=9999 -Dapp.adminPassword=password -Dapp.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dapp.events.maxSize=0\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\n## Format the sources\n\nfrom the root of your repository run\n\n```sh\nsh ./scripts/fmt.sh\n```"},{"name":"features.md","id":"/features.md","url":"/features.html","title":"Features ","content":"# Features \n\n@@@ warning\nThis section is under construction\n@@@\n\nAll the features supported by **Otoroshi** are listed below\n\n* Dynamic changes at runtime without full reload \n* Can proxy any HTTP/HTTP2 server (websockets and streamed responses included)\n* Full featured admin Rest Api to control Otoroshi the way you want. Included, Swagger descriptor\n* Gorgeous React Web UI\n* Full end-to-end streaming of HTTP requests and responses\n* Completely non blocking and async internals\n* @ref:[Official Docker image](./getotoroshi/fromdocker.md)\n* @ref:[Multi backend datastore support](./firstrun/datastore.md)\n * Redis\n * In memory\n * Cassandra (experimental support)\n * filedb (not suitable for production usage)\t\n* Pluggable modules system (plugins) \n * you can create your own modules to change de behavior of Otoroshi per service or globally\n * impacts on access validation, routing, body transformation, apikey extraction\n * listen to internal otoroshi events\n * modules can be written and deployed from the UI\n * lot of module provided out of the box (see TODO:)\n* Full featured TLS integration\n * @ref:[Dynamic SSL termination](./topics/ssl.md)\n * mTLS support for input and output connections (end-to-end mTLS)\n * extended client certificate validation\n * TLS certificate automation (create, renew, etc) based on a CA certificate\n * ACME/Let's Encrypt support (create, renew)\n * on-the-fly certificate generation based on a CA certificate without request loss\n* Classic features for reverse proxying\n * expose the same service on multiple domain names (including wildcards)\n * support multiple loadbalancing algorithms\n * configurable circuit breaker per service, with timeouts per path and verb\n * @ref:[maintenance page per service](./usage/2-services.md)\n * @ref:[build page per service](./usage/2-services.md)\n * @ref:[force HTTPS usage per service](./usage/2-services.md)\n * @ref:[Add current Api key quotas usage in response headers](./usage/3-apikeys.md)\n * @ref:[Add current latencies in response headers](./usage/3-apikeys.md)\n * headers manipulation\n * routing headers\n * custom html error templates\n * healthcheck per service\n * sink services\n * CORS support\n * GZIP support\n * filtering on http verb and path\n* Api management features\n * throttling / daily quotas / monthly quotas per apikey\n * apikey authorization based on http verb and path\n * global throttling\n * global throttling per ip address\n * global or per service ip address blacklist / whitelist\n * automatic apikey secret rotation\n* Authentication modules\n * LDAP\n * In memory (managed by otoroshi)\n * OAuth2/OIDC\n * modules can be used for admin. backoffice login\n * webauthentication support\n * sessions management from UI\n* JWT token utilities\n * validate incoming JWT tokens\n * transform incoming JWT tokens\n * chain multiple validators\n* Analytics / Metrics\n * rich traffic events for each proxied http request\n * @ref:[Live metrics per service and globaly](./usage/4-monitor.md) \n * @ref:[Global metrics and analytics (requires elastic server)](./usage/7-metrics.md)\n * @ref:[Traffic events can be sent using webhooks or Kafka topic](./setup/dangerzone.md#analytics-settings)\n * multiple technical metrics exporters (statsd, datadog, prometheus)\n* Audit trail\n * @ref:[Global audit log alert log on admins actions](./usage/6-audit.md)\n * @ref:[Audit and alerts events can be sent using webhooks or Kafka topic](./setup/dangerzone.md#analytics-settings)\n * @ref:[Alerts events can be send to people by email using email provider (Mailgun, mailjet)](./integrations/mailgun.md)\n* Extract informations from `User-Agent` headers to enrich traffic events\n* Extract geolocation informations (need external service) to enrich traffic events\n* Support enterprise http proxies globaly and per service\n* TCP proxy with SNI and TLS passthrought support\n* TCP / UDP tunnelings\n * add web authentication on top of anything\n * local tunnel client with CLI or UI\n* @ref:[Canary mode per service](./topics/snow-monkey.md)\n* @ref:[Chaos engineering tools with the Snow Monkey](./topics/snow-monkey.md)\n* @ref:[Advanced CleverCloud integration (create services from CleverCloud apps)](./integrations/clevercloud.md) \n"},{"name":"configfile.md","id":"/firstrun/configfile.md","url":"/firstrun/configfile.html","title":"Config. with files","content":"# Config. with files\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## Common configuration\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.domain` | string | \"oto.tools\" | the domain on which Otoroshi UI/API is be exposed|\n| `app.rootScheme` | string | \"http\" | the scheme on which Otoroshi is exposed, either \"http\" or \"https\" |\n| `app.snowflake.seed` | number | 0 | this number will is used to generate unique ids across the cluster. Each Otorshi instance must have a unique seed. |\n| `app.events.maxSize` | number | 1000 | max number of analytic and alert events stored locally |\n| `app.backoffice.exposed` | boolean | true | does the current Otoroshi instance exposed a backoffice ui|\n| `app.backoffice.subdomain` | string | \"otoroshi\" | the subdomain on wich Otoroshi backoffice will be served |\n| `app.backoffice.session.exp` | number | 86400000 | the number of seconds before the Otoroshi backoffice session expires |\n| `app.privateapps.subdomain` | string | \"privateapps\" | the subdomain on which private apps UI are served |\n| `app.privateapps.session.exp` | number | 86400000 | the number of seconds before the private apps session expires |\n| `app.claim.sharedKey` | string | \"secret\" | the shared secret used for signing the JWT token passed between Otoroshi and backend services |\n| `app.webhooks.size` | number | 100 | number of events sent at most when calling one of the analytics webhooks |\n| `app.throttlingWindow` | number | 10 | time window (in seconds) used to compute throttling quotas for ApiKeys |\n\n## Admin API configuration\n\nWhen Otoroshi starts for the first time, its datastore is empty. As Otoroshi uses Otoroshi to expose its admin REST API, you'll have to provide the details for the admin API exposition. **This part is super important** because if you go to production with the default values, your Otoroshi server won't be secured anymore.\n\n@@@ warning\nYOU HAVE TO CUSTOMIZE THE FOLLOWING VALUES BEFORE GOING TO PRODUCTION !!\n@@@\n\nSome of the following terms will seem obscure to you, but you will learn their meaning in the following chapters :)\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.adminapi.exposed` | boolean | true | does the current Otoroshi instance expose an admin API |\n| `app.adminapi.targetSubdomain` | string | \"otoroshi-admin-internal-api\" | the subdomain on wich admin API call will be redirected from `app.adminapi.exposedSubdomain` |\n| `app.adminapi.exposedSubdomain` | string | \"otoroshi-api\" | the subdomain on wich the Otoroshi admin API will be exposed |\n| `app.adminapi.defaultValues.backOfficeGroupId` | string | \"admin-api-group\" | the name of the service groups that will contain the service descriptors for the Otoroshi admin API |\n| `app.adminapi.defaultValues.backOfficeApiKeyClientId` | string | \"admin-api-apikey-id\" | the client id of the Otoroshi admin API apikey |\n| `app.adminapi.defaultValues.backOfficeApiKeyClientSecret` | string | \"admin-api-apikey-secret\" | the client secret of the Otoroshi admin API apikey |\n| `app.adminapi.defaultValues.backOfficeServiceId` | string | \"admin-api-service\" | the id of the service descriptors for the Otoroshi admin API |\n| `app.adminapi.proxy.https` | boolean | false | whether or not the current Otoroshi instance serves its content over https. This setting is useful for the backoffice UI to access Otoroshi admin API |\n| `app.adminapi.proxy.local` | boolean | true | whether or not the admin API is accessible through `127.0.0.1`. This setting is useful for the backoffice UI to access Otoroshi admin API |\n\n## Secrets config\n\nWhen Otoroshi starts for the first time, its secrets are set by default. \n\n@@@ warning\nYOU HAVE TO CUSTOMIZE AT LEAST `otoroshi.secret` BEFORE GOING TO PRODUCTION !!\n@@@\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `otoroshi.secret` | string | 'verysecretvaluethatyoumustoverwrite' | default Otoroshi secret. This value is used by default for other secrets |\n| `otoroshi.sessions.secret` | string | `otoroshi.secret` | Secret used to cipher session ids |\n| `play.http.secret.key` | string | `otoroshi.secret` | the secret used to sign Otoroshi session cookie |\n\n## DB configuration\n\nAs Otoroshi supports multiple datastores, you'll have to provide some details about how to connect/configure it.\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `app.storage` | string | \"inmemory\" | what kind of storage engine you want to use. Possible values are `inmemory`, `file`, `redis`, `cassandra` |\n| `app.importFrom` | string | | a file path or a URL to an Otoroshi export file. If the datastore is empty on startup, this file will be used to import data to the empty DB |\n| `app.importFromHeaders` | array | [] | a list of `:` separated header to use if the `app.importFrom` setting is a URL |\n| `app.initialData` | object |  | object representing Otoroshi internal data as exported from danger zone so you don't need a config file and a data import file |\n| `app.redis.host` | string | \"localhost\" | the host of the redis server |\n| `app.redis.port` | number | 6379 | the port of the redis server |\n| `app.redis.slaves` | array | [] | the redis slaves lists |\n| `app.filedb.path` | string | \"./filefb\" | the path where filedb files will be written |\n| `app.cassandra.hosts` | string | \"127.0.0.1\" | the host of the cassandra server |\n| `app.cassandra.host` | string | \"127.0.0.1\" | the list of cassandra hosts |\n| `app.cassandra.port` | number | 9042 | the port of the cassandra servers |\n| `app.pg.uri` | string | | the uri of your pg database |\n| `app.pg.host` | string | localhost | the host of your pg database |\n| `app.pg.port` | number | 5432 | the port of your pg database |\n| `app.pg.database` | string | otoroshi | the database name |\n| `app.pg.user` | string | otoroshi | the username to connect to your pg database |\n| `app.pg.password` | string | otoroshi | the password to connect to your pg database |\n\n## Headers configuration\n\nOtoroshi uses a fair amount of http headers in order to work properly. The name of those headers are customizable to fit your needs.\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `otoroshi.headers.trace.label` | string | \"Otoroshi-Viz-From-Label\" | header to pass request tracing informations |\n| `otoroshi.headers.trace.from` | string | \"Otoroshi-Viz-From\" | header to pass request tracing informations (ip address) |\n| `otoroshi.headers.trace.parent` | string | \"Otoroshi-Parent-Request\" | header to pass request tracing informations (parent request id) |\n| `otoroshi.headers.request.adminprofile` | string | \"Otoroshi-Admin-Profile\" | header to pass admin name when the admin API is called from the Otoroshi backoffice |\n| `otoroshi.headers.request.clientid` | string | \"Otoroshi-Client-Id\" | header to pass apikey client id |\n| `otoroshi.headers.request.clientsecret` | string | \"Otoroshi-Client-Secret\" | header to pass apikey client secret |\n| `otoroshi.headers.request.id` | string | \"Otoroshi-Request-Id\" | header containing the id of the current request |\n| `otoroshi.headers.response.proxyhost` | string | \"Otoroshi-Proxied-Host\" | header containing the proxied host |\n| `otoroshi.headers.response.error` | string | \"Otoroshi-Error\" | header containing whether or not the request generated an error |\n| `otoroshi.headers.response.errormsg` | string | \"Otoroshi-Error-Msg\" | header containing error message if some |\n| `otoroshi.headers.response.proxylatency` | string | \"Otoroshi-Proxy-Latency\" | header containing the current latency induced by Otoroshi |\n| `otoroshi.headers.response.upstreamlatency` | string | \"Otoroshi-Upstream-Latency\" | header containing the current latency from Otoroshi to service backend |\n| `otoroshi.headers.response.dailyquota` | string | \"Otoroshi-Daily-Calls-Remaining\" | header containing the number of remaining daily call (apikey) |\n| `otoroshi.headers.response.monthlyquota` | string | \"Otoroshi-Monthly-Calls-Remaining\" | header containing the number of remaining monthly call (apikey) |\n| `otoroshi.headers.comm.state` | string | \"Otoroshi-State\" | header containing a random value for secured mode |\n| `otoroshi.headers.comm.stateresp` | string | \"Otoroshi-State-Resp\" | header containing a random value for secured mode |\n| `otoroshi.headers.comm.claim` | string | \"Otoroshi-Claim\" | header containing a JWT token for secured mode |\n| `otoroshi.headers.healthcheck.test` | string | \"Otoroshi-Health-Check-Logic-Test\" | header containing a logic test for healthcheck |\n| `otoroshi.headers.healthcheck.testresult` | string | \"Otoroshi-Health-Check-Logic-Test-Result\" | header containing the result of a logic test for healthcheck |\n| `otoroshi.headers.jwt.issuer` | string | \"Otoroshi\" | the name of the issuer for the JWT token |\n| `otoroshi.headers.canary.tracker` | string | \"Otoroshi-Canary-Id\" | header containing the ID of the canary session if enabled |\n\n## Play specific configuration\n\nAs Otoroshi is a [Play app](https://www.playframework.com/), you should take a look at [Play configuration documentation](https://www.playframework.com/documentation/2.6.x/Configuration) to tune its internal configuration\n\n| name | type | default value | description |\n| ---- |:----:| -------------- | ----- |\n| `http.port` | number | 8080 | the http port used by Otoroshi. You can use 'disabled' as value if you don't want to use http |\n| `https.port` | number | disabled | the https port used by Otoroshi. You can use 'disabled' as value if you don't want to use https |\n| `http2.enabled` | boolean | false | whether or not http2 is enabled on the Otoroshi server. You need to configure https (listed bellow) to be able to use it |\n| `play.http.secret.key` | string | \"secret\" | the secret used to sign Otoroshi session cookie |\n| `play.http.session.secure` | boolean | false | whether or not the Otoroshi backoffice session will be served over https only |\n| `play.http.session.httpOnly` | boolean | true | whether or not the Otoroshi backoffice session will be accessible from Javascript |\n| `play.http.session.maxAge` | number | 259200000 | the number of seconds before Otoroshi backoffice session expired |\n| `play.http.session.domain` | string | \".oto.tools\" | the domain on which the Otoroshi backoffice session is authorized |\n| `play.http.session.cookieName` | string | \"otoroshi-session\" | the name of the Otoroshi backoffice session |\n| `play.ws.play.ws.useragent` | string | \"Otoroshi\" | the user agent sent by Otoroshi if not present on the original http request |\n| `play.server.https.keyStore.path` | string | | the path to the keystore containing the private key and certificate, if not provided generates a keystore for you |\n| `play.server.https.keyStore.type` | string | JKS | the key store type, defaults to JKS |\n| `play.server.https.keyStore.password` | string | '' | the password, defaults to a blank password |\n| `play.server.https.keyStore.algorithm` | string | | the key store algorithm, defaults to the platforms default algorithm |\n\n## More config. options\n\nSee https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/base.conf and https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/application.conf\n\nif you want to configure https on your Otoroshi server, just read [PlayFramework documentation about it](https://www.playframework.com/documentation/2.6.x/ConfiguringHttps)\n\n## Example of a custom. configuration file\n\n```conf\ninclude \"application.conf\"\n\nhttp.port = 8080\n\napp {\n storage = \"file\"\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) "},{"name":"datastore.md","id":"/firstrun/datastore.md","url":"/firstrun/datastore.html","title":"Choose your datastore","content":"# Choose your datastore\n\nRight now, Otoroshi supports multiple datastore.\n\nYou can choose one datastore over another depending on your use case.\n\nAvailable datastores are the following :\n\n* in memory\n* redis\n* cassandra (experimental support, should be used in cluster mode for leaders)\n* postgresql or any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)\n* filedb (not suitable for production usage)\n\nThe **filedb** datastore is pretty handy for testing purposes, but is not supposed to be used in production mode.\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. You can check the clustering documentation to find more about it.\n\nThe **redis** datastore is quite nice when you want to easily deploy several Otoroshi instances.\n\nIf you need a datastore more scalable than redis, then you can use the **postgresql** or **cassandra** datastore.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"env.md","id":"/firstrun/env.md","url":"/firstrun/env.html","title":"Config. with ENVs","content":"# Config. with ENVs\n\nNow that you know @ref:[how to configure Otoroshi with the config. file](./configfile.md) every property in the following block can be overriden by an environment variable (an env. variable is written like `${?ENV_VARIABLE}`).\n\n## Reference configuration for env. variables\n\n@@snip [reference-env.conf](../snippets/reference-env.conf) \n"},{"name":"host.md","id":"/firstrun/host.md","url":"/firstrun/host.html","title":"Setup your hosts","content":"# Setup your hosts\n\nBy default, Otoroshi starts with domain `oto.tools` that targets `127.0.0.1`. Of course you can change the domain, you have to add the values in your `/etc/hosts` file according to the setting you put in Otoroshi configuration\n\n* `app.domain` => `oto.tools`\n* `app.backoffice.subdomain` => `otoroshi`\n* `app.privateapps.subdomain` => `privateapps`\n* `app.adminapi.exposedSubdomain` => `otoroshi-api`\n* `app.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 -Dapp.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 `app.domain` and the settings listed on this page and in the * @ref:[Config. with files page](./configfile.md) that serve Otoroshi API and UI on `http://otoroshi-api.${app.domain}` and `http://otoroshi.${app.domain}`.\nOnce the descriptor is saved in database, if you want to change `app.domain`, you'll have to edit the descriptor in the database or restart Otoroshi with an empty database.\n@@@\n"},{"name":"index.md","id":"/firstrun/index.md","url":"/firstrun/index.html","title":"First run","content":"# First run\n\nNow that you have your own distro of Otoroshi, it's time to run it. \n\nBut before doing so, you'll have to make some choices about some essential stuff in order to have your own customized version of Otoroshi.\n\nLet's start with the datastore\n\n\n@@@ index\n\n* [choose a datastore](./datastore.md)\n* [use custom config file](./configfile.md)\n* [use ENV](./env.md)\n* [initial state](./initialstate.md)\n* [Hosts](./host.md)\n* [Run](./run.md)\n\n@@@"},{"name":"initialstate.md","id":"/firstrun/initialstate.md","url":"/firstrun/initialstate.html","title":"Import initial state","content":"# Import initial state\n\nNow you are almost ready to run Otoroshi for the first time, but maybe you want to import data from previous Otoroshi installation in your current datastore.\n\nTo do that, you need to add the `app.importFrom` setting to the Otoroshi configuration (of `$APP_IMPORT_FROM` env).\n\nIt can be a file path or a URL\n\n## Example of export\n\n```json\n{\n \"config\": {\n \"lines\": [\"prod\"], \n \"limitConcurrentRequests\": true,\n \"maxConcurrentRequests\": 500,\n \"useCircuitBreakers\": true,\n \"apiReadOnly\": false,\n \"registerFromCleverHook\": false,\n \"u2fLoginOnly\": true,\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"throttlingQuota\": 100000,\n \"perIpThrottlingQuota\": 500,\n \"analyticsEventsUrl\": null,\n \"analyticsWebhooks\": [],\n \"alertsWebhooks\": [],\n \"alertsEmails\": [],\n \"endlessIpAddresses\": []\n },\n \"admins\": [],\n \"simpleAdmins\": [\n {\n \"username\": \"admin@otoroshi.io\",\n \"password\": \"xxxxxxxxxxxxxxxxx\",\n \"label\": \"Otoroshi Admin\",\n \"createdAt\": 1493971715708\n }\n ],\n \"serviceGroups\": [\n {\n \"id\": \"default\",\n \"name\": \"default-group\",\n \"description\": \"The default group\"\n },\n {\n \"id\": \"admin-api-group\",\n \"name\": \"Otoroshi Admin Api group\",\n \"description\": \"No description\"\n }\n ],\n \"apiKeys\": [\n {\n \"clientId\": \"admin-api-apikey-id\",\n \"clientSecret\": \"admin-api-apikey-secret\",\n \"clientName\": \"Otoroshi Backoffice ApiKey\",\n \"authorizedEntities\": [\"group_admin-api-group\"],\n \"enabled\": true,\n \"throttlingQuota\": 10000000,\n \"dailyQuota\": 10000000,\n \"monthlyQuota\": 10000000,\n \"metadata\": {}\n }\n ],\n \"serviceDescriptors\": [\n {\n \"id\": \"admin-api-service\",\n \"groupId\": \"admin-api-group\",\n \"name\": \"otoroshi-admin-api\",\n \"env\": \"prod\",\n \"domain\": \"oto.tools\",\n \"subdomain\": \"otoroshi-api\",\n \"targets\": [\n {\n \"host\": \"localhost:8080\",\n \"scheme\": \"http\"\n }\n ],\n \"root\": \"/\",\n \"enabled\": true,\n \"privateApp\": false,\n \"forceHttps\": false,\n \"maintenanceMode\": false,\n \"buildMode\": false,\n \"enforceSecureCommunication\": true,\n \"publicPatterns\": [],\n \"privatePatterns\": [],\n \"additionalHeaders\": {\n \"Host\": \"otoroshi-admin-internal-api.oto.tools\"\n },\n \"matchingHeaders\": {},\n \"ipFiltering\": {\n \"whitelist\": [],\n \"blacklist\": []\n },\n \"api\": {\n \"exposeApi\": false\n },\n \"healthCheck\": {\n \"enabled\": false,\n \"url\": \"/\"\n },\n \"metadata\": {}\n }\n ],\n \"errorTemplates\": []\n}\n```\n"},{"name":"run.md","id":"/firstrun/run.md","url":"/firstrun/run.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\nunzip otoroshi-dist.zip\ncd otoroshi-vx.x.x\n./bin/otoroshi\n```\n\n## From .jar file\n\nFor Java 8 & Java 11\n\n```sh\njava -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](../firstrun/configfile.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](../firstrun/env.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 -Dapp.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 -Dapp.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 -Dapp.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":"frombinaries.md","id":"/getotoroshi/frombinaries.md","url":"/getotoroshi/frombinaries.html","title":"From binaries","content":"# From binaries\n\nIf you want to download the last version of Otoroshi and its CLI, you can grab them from the release page of the Otoroshi github page :\n\nGo to https://github.com/MAIF/otoroshi/releases and get the last version of the `otoroshi-dist.zip` file or `otoroshi.jar` file\n"},{"name":"fromdocker.md","id":"/getotoroshi/fromdocker.md","url":"/getotoroshi/fromdocker.html","title":"From docker","content":"# From docker\n\nIf you're a Docker aficionado, Otoroshi is provided as a Docker image that your can pull directly from Official repos.\n\nfirst, fetch the last Docker image of Otoroshi :\n\n```sh\ndocker pull maif/otoroshi:1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:latest\n# or \ndocker pull maif/otoroshi:jdk8-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk11-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk12-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk13-1.5.0-rc.2\n# or \ndocker pull maif/otoroshi:jdk14-1.5.0-rc.2\n```"},{"name":"fromsources.md","id":"/getotoroshi/fromsources.md","url":"/getotoroshi/fromsources.html","title":"From sources","content":"# From sources\n\nto build Otoroshi from sources, you need the following tools :\n\n* git\n* JDK 8\n* SBT\n* node\n* yarn\n\nOnce you've installed all those tools, go to the [Otoroshi github page](https://github.com/MAIF/otoroshi) and clone the sources :\n\n```sh\ngit clone https://github.com/MAIF/otoroshi.git --depth=1\n```\n\nthen you need to run the `build.sh` script to build the documentation, the React UI and the server :\n\n```sh\nsh ./scripts/build.sh\n```\n\nand that's all, you can grab your Otoroshi package at `otoroshi/target/scala-2.12/otoroshi` or `otoroshi/target/universal/`.\n\nFor those who want to build only parts of Otoroshi, read the following.\n\n## Build the documentation only\n\nGo to the `documentation` folder and run :\n\n```sh\nsbt ';clean;paradox'\n```\n\nThe documentation is located at `manual/target/paradox/site/main/`\n\n## Build the React UI\n\nGo to the `otoroshi/javascript` folder and run :\n\n```sh\nyarn install\nyarn build\n```\n\nYou will find the JS bundle at `otoroshi/public/javascripts/bundle/bundle.js`.\n\n## Build the Otoroshi server\n\nGo to the `otoroshi` folder and run :\n\n```sh\nexport SBT_OPTS=\"-Xmx2G -Xss6M\"\nsbt ';clean;compile;dist;assembly'\n```\n\nYou will find your Otoroshi package at `otoroshi/target/scala-2.12/otoroshi` or `otoroshi/target/universal/`.\n"},{"name":"index.md","id":"/getotoroshi/index.md","url":"/getotoroshi/index.html","title":"Get Otoroshi","content":"# Get Otoroshi\n\nThere are several ways to get Otoroshi to run it on your system.\n\nLet's start with a good old build from sources :)\n\n@@@ index\n\n* [from sources](./fromsources.md)\n* [from binaries](./frombinaries.md)\n* [from docker](./fromdocker.md)\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.0-rc.2/otoroshi.jar)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\n## Installation\n\nYou can download the latest build of Otoroshi as a [fat jar](https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi.jar), as a [zip package](https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi-dist.zip) or as a @ref:[docker image](./getotoroshi/fromdocker.md).\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.0-rc.2/otoroshi.jar'\njava -jar otoroshi.jar\n```\n\nor using docker\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi:1.5.0-rc.2\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](./quickstart.md) or directly to the @ref:[installation instructions](./getotoroshi/index.md)\n\n## Documentation\n\n* @ref:[About Otoroshi](./about.md)\n* @ref:[Architecture](./archi.md)\n* @ref:[Features](./features.md)\n* @ref:[Try Otoroshi in 5 minutes](./quickstart.md)\n* @ref:[Get Otoroshi](./getotoroshi/index.md)\n* @ref:[First run](./firstrun/index.md)\n* @ref:[Setup Otoroshi](./setup/index.md)\n* @ref:[Using Otoroshi](./usage/index.md)\n* @ref:[Third party Integrations](./integrations/index.md)\n* @ref:[Detailed topics](./topics/index.md)\n* @ref:[Admin REST API](./api.md)\n* @ref:[Deploy to production](./deploy/index.md)\n* @ref:[Developing Otoroshi](./dev.md)\n\n## Discussion\n\nJoin the [Otoroshi](https://gitter.im/MAIF/otoroshi) channel on the [MAIF Gitter](https://gitter.im/MAIF)\n\n## Sources\n\nThe sources of Otoroshi are available on [Github](https://github.com/MAIF/otoroshi).\n\n## Logo\n\nYou can find the official Otoroshi logo [on GitHub](https://github.com/MAIF/otoroshi/blob/master/resources/otoroshi-logo.png). 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 [Github Releases](https://github.com/MAIF/otoroshi/releases) page. A condensed version of the changelog is available on [github]((https://github.com/MAIF/otoroshi/CHANGELOG.md)\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 [Apache 2 License](https://opensource.org/licenses/Apache-2.0) \n\n@@@ index\n\n* [About Otoroshi](about.md)\n* [Architecture](archi.md)\n* [Features](features.md)\n* [Quickstart](quickstart.md)\n* [Get otoroshi](getotoroshi/index.md)\n* [First run](firstrun/index.md)\n* [Setup](setup/index.md)\n* [Using Otoroshi](usage/index.md)\n* [Integrations](integrations/index.md)\n* [Detailed topics](topics/index.md)\n* [Admin REST API](api.md)\n* [Deploy to production](deploy/index.md)\n* [Developing Otoroshi](./dev.md)\n* [Otoroshi plugins](./plugins/index.md) \n\n@@@\n"},{"name":"analytics.md","id":"/integrations/analytics.md","url":"/integrations/analytics.html","title":"Analytics","content":"# Analytics\n\nEach action and request on Otoroshi creates events that can be sent outside of Otoroshi for further usage. Those events can be sent using a webhook and/or through a Kafka topic.\n\n## Push events to Elasticsearch\n\n@@@ warning\nOtoroshi supports only Elasticsearch versions under 7.0\n@@@\n\nYou can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (write)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Read events from Elasticsearch\n\nYou can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic dashboard datasource (read)` section.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Push events to WebHooks\n\nGo to `settings (cog icon) / Danger Zone` and expand the `Analytics: Webhooks` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nHere you can configure the URL of the webhook and its headers if needed.\n\n## Push events to Kafka\n\nEvents can also be sent through a Kafka topic. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Kafka` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form, default values for topic names are :\n\n* `otoroshi-alerts`\n* `otoroshi-analytics`\n* `otoroshi-audits`\n\n@@@ warning\nIf you use trustore/keystore to access your kafka instances, the paths should be absolute and refers to host paths. You can also choose a client certificate from otoroshi for client authentication.\n@@@\n"},{"name":"clevercloud.md","id":"/integrations/clevercloud.md","url":"/integrations/clevercloud.html","title":"Clever Cloud","content":"# Clever Cloud\n\nOtoroshi provides an integration with Clever Cloud to create easily services based on application deployed on your Clever Cloud account.\nGo to `settings (cog icon) / Danger Zone` and expand the `CleverCloud settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form with your CleverCloud credentials (https://www.clever-cloud.com/doc/clever-cloud-apis/cc-api/) and your CleverCloud `organization id`.\n\nOnce it's done, you will see a new menu in the side bar.\n\n@@@ div { .centered-img }\n\n@@@\n\nIf you click on it, you'll see a page listing all your apps deployed on Clever Cloud with buttons to create new services with the app as the target.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou will also see a new button in the `Target` section of services to attach Clever Cloud applications as target for a service.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"index.md","id":"/integrations/index.md","url":"/integrations/index.html","title":"Third party Integrations","content":"# Third party Integrations\n\nOtoroshi provides some settings to interact with some third party systems.\n\n@@@ index\n\n* [Analytics](./analytics.md)\n* [Mailgun / Mailjet](./mailgun.md)\n* [StatsD / Datadog](./statsd.md)\n* [clevercloud](./clevercloud.md)\n\n@@@\n"},{"name":"mailgun.md","id":"/integrations/mailgun.md","url":"/integrations/mailgun.html","title":"Mailgun","content":"# Mailgun\n\nIf you want to receive Otoroshi alert by emails, you have to configure Otoroshi with your Mailgun credentials. Go to `settings (cog icon) / Danger Zone` and expand the `Mailgun settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFill the form with provided information on the `domain informations` page on Mailgun located at https://app.mailgun.com/app/domains/my.domain.\n\nThen, expand the `Alert settings` section and add email addresses separated by comma in the `Alert emails` field. **Don't forget to save.**\n\n@@@ div { .centered-img }\n\n@@@\n\n# Mailjet\n\nOtoroshi also supports Mailjet. Just select `Mailjet` in `Mailer settings type` and fill the requested fields."},{"name":"statsd.md","id":"/integrations/statsd.md","url":"/integrations/statsd.html","title":"StatsD / Datadog","content":"# StatsD / Datadog\n\nOtoroshi provides a StatsD integration to monitor some technical metrics across all your Otoroshi instances.\nGo to `settings (cog icon) / Danger Zone` and expand the `Statsd settings` section.\n\n@@@ div { .centered-img }\n\n@@@\n\nAdd the host and port of the Statsd agent on your system.\nIf you're using Datadog, don't forget to check the `Datadog` switch.\n"},{"name":"index.md","id":"/plugins/index.md","url":"/plugins/index.html","title":"Otoroshi plugins","content":"# Otoroshi plugins\n\nOtoroshi provides some plugins out of the box\n\n* @ref:[Access log (CLF)](./otoroshi-plugins-accesslog-accesslog.md)\n* @ref:[Access log (JSON)](./otoroshi-plugins-accesslog-accesslogjson.md)\n* @ref:[Allowed users only](./otoroshi-plugins-users-hasallowedusersvalidator.md)\n* @ref:[Apikey auth module](./otoroshi-plugins-apikeys-apikeyauthmodule.md)\n* @ref:[Apikey from Biscuit token extractor](./otoroshi-plugins-biscuit-biscuitextractor.md)\n* @ref:[Basic Auth. caller](./otoroshi-plugins-authcallers-basicauthcaller.md)\n* @ref:[Biscuit token validator](./otoroshi-plugins-biscuit-biscuitvalidator.md)\n* @ref:[Body logger](./otoroshi-plugins-loggers-bodylogger.md)\n* @ref:[Client Certificate + Api Key only](./otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md)\n* @ref:[Client Certificate Only](./otoroshi-plugins-clientcert-hasclientcertvalidator.md)\n* @ref:[Client Credential Flow ApiKey extractor](./otoroshi-plugins-apikeys-clientcredentialflowextractor.md)\n* @ref:[Client Credential Service](./otoroshi-plugins-apikeys-clientcredentialservice.md)\n* @ref:[Client certificate as apikey](./otoroshi-plugins-apikeys-certificateasapikey.md)\n* @ref:[Client certificate header](./otoroshi-plugins-clientcert-clientcertchainheader.md)\n* @ref:[Client certificate matching](./otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md)\n* @ref:[Client certificate matching (over http)](./otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md)\n* @ref:[Defer Responses](./otoroshi-plugins-defer-deferplugin.md)\n* @ref:[Envoy Control Plane (experimental)](./otoroshi-plugins-envoy-envoycontrolplane.md)\n* @ref:[External Http Validator](./otoroshi-plugins-external-externalhttpvalidator.md)\n* @ref:[Geolocation details extractor (using IpStack api)](./otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md)\n* @ref:[Geolocation details extractor (using Maxmind db)](./otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md)\n* @ref:[Geolocation endpoint](./otoroshi-plugins-geoloc-geolocationinfoendpoint.md)\n* @ref:[Geolocation header](./otoroshi-plugins-geoloc-geolocationinfoheader.md)\n* @ref:[Global self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationsink.md)\n* @ref:[HMAC access validator](./otoroshi-plugins-hmac-hmacvalidator.md)\n* @ref:[HMAC caller plugin](./otoroshi-plugins-hmac-hmaccallerplugin.md)\n* @ref:[Html Patcher](./otoroshi-plugins-jsoup-htmlpatcher.md)\n* @ref:[Instance quotas](./otoroshi-plugins-quotas-instancequotas.md)\n* @ref:[Izanami APIs Proxy](./otoroshi-plugins-izanami-izanamiproxy.md)\n* @ref:[Izanami Canary Campaign](./otoroshi-plugins-izanami-izanamicanary.md)\n* @ref:[Jwt user extractor](./otoroshi-plugins-jwt-jwtuserextractor.md)\n* @ref:[Kafka access log](./otoroshi-plugins-accesslog-kafkaaccesslog.md)\n* @ref:[Kubernetes Ingress Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md)\n* @ref:[Kubernetes Otoroshi CRDs Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md)\n* @ref:[Kubernetes admission validator webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md)\n* @ref:[Kubernetes sidecar injector webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md)\n* @ref:[Kubernetes to Otoroshi certs. synchronizer](./otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md)\n* @ref:[Mirroring plugin](./otoroshi-plugins-mirror-mirroringplugin.md)\n* @ref:[OAuth1 caller](./otoroshi-plugins-oauth1-oauth1callerplugin.md)\n* @ref:[OAuth2 caller](./otoroshi-plugins-authcallers-oauth2caller.md)\n* @ref:[OIDC access_token as apikey](./otoroshi-plugins-oidc-oidcaccesstokenasapikey.md)\n* @ref:[OIDC access_token validator](./otoroshi-plugins-oidc-oidcaccesstokenvalidator.md)\n* @ref:[OIDC headers](./otoroshi-plugins-oidc-oidcheaders.md)\n* @ref:[Otoroshi certs. to Kubernetes secrets synchronizer](./otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md)\n* @ref:[Prometheus Endpoint](./otoroshi-plugins-metrics-prometheusendpoint.md)\n* @ref:[Prometheus Service Metrics](./otoroshi-plugins-metrics-prometheusservicemetrics.md)\n* @ref:[Public quotas](./otoroshi-plugins-quotas-servicequotas.md)\n* @ref:[Response Cache](./otoroshi-plugins-cache-responsecache.md)\n* @ref:[Security Txt](./otoroshi-plugins-security-securitytxt.md)\n* @ref:[Self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md)\n* @ref:[Service Metrics](./otoroshi-plugins-metrics-servicemetrics.md)\n* @ref:[Service discovery target selector (service discovery)](./otoroshi-plugins-discovery-discoverytargetsselector.md)\n* @ref:[Static Response](./otoroshi-plugins-static-staticresponse.md)\n* @ref:[User-Agent details extractor](./otoroshi-plugins-useragent-useragentextractor.md)\n* @ref:[User-Agent endpoint](./otoroshi-plugins-useragent-useragentinfoendpoint.md)\n* @ref:[User-Agent header](./otoroshi-plugins-useragent-useragentinfoheader.md)\n* @ref:[Workflow endpoint](./otoroshi-plugins-workflow-workflowendpoint.md)\n* @ref:[Workflow job](./otoroshi-plugins-workflow-workflowjob.md)\n\n@@@ index\n\n* [Access log (CLF)](./otoroshi-plugins-accesslog-accesslog.md)\n* [Access log (JSON)](./otoroshi-plugins-accesslog-accesslogjson.md)\n* [Allowed users only](./otoroshi-plugins-users-hasallowedusersvalidator.md)\n* [Apikey auth module](./otoroshi-plugins-apikeys-apikeyauthmodule.md)\n* [Apikey from Biscuit token extractor](./otoroshi-plugins-biscuit-biscuitextractor.md)\n* [Basic Auth. caller](./otoroshi-plugins-authcallers-basicauthcaller.md)\n* [Biscuit token validator](./otoroshi-plugins-biscuit-biscuitvalidator.md)\n* [Body logger](./otoroshi-plugins-loggers-bodylogger.md)\n* [Client Certificate + Api Key only](./otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md)\n* [Client Certificate Only](./otoroshi-plugins-clientcert-hasclientcertvalidator.md)\n* [Client Credential Flow ApiKey extractor](./otoroshi-plugins-apikeys-clientcredentialflowextractor.md)\n* [Client Credential Service](./otoroshi-plugins-apikeys-clientcredentialservice.md)\n* [Client certificate as apikey](./otoroshi-plugins-apikeys-certificateasapikey.md)\n* [Client certificate header](./otoroshi-plugins-clientcert-clientcertchainheader.md)\n* [Client certificate matching](./otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md)\n* [Client certificate matching (over http)](./otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md)\n* [Defer Responses](./otoroshi-plugins-defer-deferplugin.md)\n* [Envoy Control Plane (experimental)](./otoroshi-plugins-envoy-envoycontrolplane.md)\n* [External Http Validator](./otoroshi-plugins-external-externalhttpvalidator.md)\n* [Geolocation details extractor (using IpStack api)](./otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md)\n* [Geolocation details extractor (using Maxmind db)](./otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md)\n* [Geolocation endpoint](./otoroshi-plugins-geoloc-geolocationinfoendpoint.md)\n* [Geolocation header](./otoroshi-plugins-geoloc-geolocationinfoheader.md)\n* [Global self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationsink.md)\n* [HMAC access validator](./otoroshi-plugins-hmac-hmacvalidator.md)\n* [HMAC caller plugin](./otoroshi-plugins-hmac-hmaccallerplugin.md)\n* [Html Patcher](./otoroshi-plugins-jsoup-htmlpatcher.md)\n* [Instance quotas](./otoroshi-plugins-quotas-instancequotas.md)\n* [Izanami APIs Proxy](./otoroshi-plugins-izanami-izanamiproxy.md)\n* [Izanami Canary Campaign](./otoroshi-plugins-izanami-izanamicanary.md)\n* [Jwt user extractor](./otoroshi-plugins-jwt-jwtuserextractor.md)\n* [Kafka access log](./otoroshi-plugins-accesslog-kafkaaccesslog.md)\n* [Kubernetes Ingress Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md)\n* [Kubernetes Otoroshi CRDs Controller](./otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md)\n* [Kubernetes admission validator webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md)\n* [Kubernetes sidecar injector webhook](./otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md)\n* [Kubernetes to Otoroshi certs. synchronizer](./otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md)\n* [Mirroring plugin](./otoroshi-plugins-mirror-mirroringplugin.md)\n* [OAuth1 caller](./otoroshi-plugins-oauth1-oauth1callerplugin.md)\n* [OAuth2 caller](./otoroshi-plugins-authcallers-oauth2caller.md)\n* [OIDC access_token as apikey](./otoroshi-plugins-oidc-oidcaccesstokenasapikey.md)\n* [OIDC access_token validator](./otoroshi-plugins-oidc-oidcaccesstokenvalidator.md)\n* [OIDC headers](./otoroshi-plugins-oidc-oidcheaders.md)\n* [Otoroshi certs. to Kubernetes secrets synchronizer](./otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md)\n* [Prometheus Endpoint](./otoroshi-plugins-metrics-prometheusendpoint.md)\n* [Prometheus Service Metrics](./otoroshi-plugins-metrics-prometheusservicemetrics.md)\n* [Public quotas](./otoroshi-plugins-quotas-servicequotas.md)\n* [Response Cache](./otoroshi-plugins-cache-responsecache.md)\n* [Security Txt](./otoroshi-plugins-security-securitytxt.md)\n* [Self registration endpoints (service discovery)](./otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md)\n* [Service Metrics](./otoroshi-plugins-metrics-servicemetrics.md)\n* [Service discovery target selector (service discovery)](./otoroshi-plugins-discovery-discoverytargetsselector.md)\n* [Static Response](./otoroshi-plugins-static-staticresponse.md)\n* [User-Agent details extractor](./otoroshi-plugins-useragent-useragentextractor.md)\n* [User-Agent endpoint](./otoroshi-plugins-useragent-useragentinfoendpoint.md)\n* [User-Agent header](./otoroshi-plugins-useragent-useragentinfoheader.md)\n* [Workflow endpoint](./otoroshi-plugins-workflow-workflowendpoint.md)\n* [Workflow job](./otoroshi-plugins-workflow-workflowjob.md)\n\n@@@\n\n\n"},{"name":"otoroshi-plugins-accesslog-accesslog.md","id":"/plugins/otoroshi-plugins-accesslog-accesslog.md","url":"/plugins/otoroshi-plugins-accesslog-accesslog.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-accesslog-accesslogjson.md","id":"/plugins/otoroshi-plugins-accesslog-accesslogjson.md","url":"/plugins/otoroshi-plugins-accesslog-accesslogjson.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-accesslog-kafkaaccesslog.md","id":"/plugins/otoroshi-plugins-accesslog-kafkaaccesslog.md","url":"/plugins/otoroshi-plugins-accesslog-kafkaaccesslog.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-apikeys-apikeyauthmodule.md","id":"/plugins/otoroshi-plugins-apikeys-apikeyauthmodule.md","url":"/plugins/otoroshi-plugins-apikeys-apikeyauthmodule.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-apikeys-certificateasapikey.md","id":"/plugins/otoroshi-plugins-apikeys-certificateasapikey.md","url":"/plugins/otoroshi-plugins-apikeys-certificateasapikey.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-apikeys-clientcredentialflowextractor.md","id":"/plugins/otoroshi-plugins-apikeys-clientcredentialflowextractor.md","url":"/plugins/otoroshi-plugins-apikeys-clientcredentialflowextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-apikeys-clientcredentialservice.md","id":"/plugins/otoroshi-plugins-apikeys-clientcredentialservice.md","url":"/plugins/otoroshi-plugins-apikeys-clientcredentialservice.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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"},{"name":"otoroshi-plugins-authcallers-basicauthcaller.md","id":"/plugins/otoroshi-plugins-authcallers-basicauthcaller.md","url":"/plugins/otoroshi-plugins-authcallers-basicauthcaller.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-authcallers-oauth2caller.md","id":"/plugins/otoroshi-plugins-authcallers-oauth2caller.md","url":"/plugins/otoroshi-plugins-authcallers-oauth2caller.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-biscuit-biscuitextractor.md","id":"/plugins/otoroshi-plugins-biscuit-biscuitextractor.md","url":"/plugins/otoroshi-plugins-biscuit-biscuitextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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 \"secret\" : \"secret\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"sealed\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n"},{"name":"otoroshi-plugins-biscuit-biscuitvalidator.md","id":"/plugins/otoroshi-plugins-biscuit-biscuitvalidator.md","url":"/plugins/otoroshi-plugins-biscuit-biscuitvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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 \"secret\" : \"secret\",\n \"checks\" : [ ],\n \"facts\" : [ ],\n \"resources\" : [ ],\n \"rules\" : [ ],\n \"revocation_ids\" : [ ],\n \"enforce\" : false,\n \"sealed\" : false,\n \"extractor\" : {\n \"type\" : \"header\",\n \"name\" : \"Authorization\"\n }\n}\n```\n\n\n\n\n\n@@@\n\n"},{"name":"otoroshi-plugins-cache-responsecache.md","id":"/plugins/otoroshi-plugins-cache-responsecache.md","url":"/plugins/otoroshi-plugins-cache-responsecache.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-clientcert-clientcertchainheader.md","id":"/plugins/otoroshi-plugins-clientcert-clientcertchainheader.md","url":"/plugins/otoroshi-plugins-clientcert-clientcertchainheader.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md","id":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.md","url":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingapikeyvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md","id":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.md","url":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchinghttpvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md","id":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.md","url":"/plugins/otoroshi-plugins-clientcert-hasclientcertmatchingvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-clientcert-hasclientcertvalidator.md","id":"/plugins/otoroshi-plugins-clientcert-hasclientcertvalidator.md","url":"/plugins/otoroshi-plugins-clientcert-hasclientcertvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-defer-deferplugin.md","id":"/plugins/otoroshi-plugins-defer-deferplugin.md","url":"/plugins/otoroshi-plugins-defer-deferplugin.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-discovery-discoveryselfregistrationsink.md","id":"/plugins/otoroshi-plugins-discovery-discoveryselfregistrationsink.md","url":"/plugins/otoroshi-plugins-discovery-discoveryselfregistrationsink.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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"},{"name":"otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md","id":"/plugins/otoroshi-plugins-discovery-discoveryselfregistrationtransformer.md","url":"/plugins/otoroshi-plugins-discovery-discoveryselfregistrationtransformer.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-discovery-discoverytargetsselector.md","id":"/plugins/otoroshi-plugins-discovery-discoverytargetsselector.md","url":"/plugins/otoroshi-plugins-discovery-discoverytargetsselector.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-envoy-envoycontrolplane.md","id":"/plugins/otoroshi-plugins-envoy-envoycontrolplane.md","url":"/plugins/otoroshi-plugins-envoy-envoycontrolplane.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-external-externalhttpvalidator.md","id":"/plugins/otoroshi-plugins-external-externalhttpvalidator.md","url":"/plugins/otoroshi-plugins-external-externalhttpvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-geoloc-geolocationinfoendpoint.md","id":"/plugins/otoroshi-plugins-geoloc-geolocationinfoendpoint.md","url":"/plugins/otoroshi-plugins-geoloc-geolocationinfoendpoint.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-geoloc-geolocationinfoheader.md","id":"/plugins/otoroshi-plugins-geoloc-geolocationinfoheader.md","url":"/plugins/otoroshi-plugins-geoloc-geolocationinfoheader.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md","id":"/plugins/otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.md","url":"/plugins/otoroshi-plugins-geoloc-ipstackgeolocationinfoextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md","id":"/plugins/otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.md","url":"/plugins/otoroshi-plugins-geoloc-maxmindgeolocationinfoextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-hmac-hmaccallerplugin.md","id":"/plugins/otoroshi-plugins-hmac-hmaccallerplugin.md","url":"/plugins/otoroshi-plugins-hmac-hmaccallerplugin.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-hmac-hmacvalidator.md","id":"/plugins/otoroshi-plugins-hmac-hmacvalidator.md","url":"/plugins/otoroshi-plugins-hmac-hmacvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-izanami-izanamicanary.md","id":"/plugins/otoroshi-plugins-izanami-izanamicanary.md","url":"/plugins/otoroshi-plugins-izanami-izanamicanary.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-izanami-izanamiproxy.md","id":"/plugins/otoroshi-plugins-izanami-izanamiproxy.md","url":"/plugins/otoroshi-plugins-izanami-izanamiproxy.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhookcrdvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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"},{"name":"otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesadmissionwebhooksidecarinjector.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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"},{"name":"otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesingresscontrollerjob.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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"},{"name":"otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetesotoroshicrdscontrollerjob.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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"},{"name":"otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-kubernetestootoroshicertsyncjob.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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"},{"name":"otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md","id":"/plugins/otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.md","url":"/plugins/otoroshi-plugins-jobs-kubernetes-otoroshitokubernetescertsyncjob.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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 \"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 \"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"},{"name":"otoroshi-plugins-jsoup-htmlpatcher.md","id":"/plugins/otoroshi-plugins-jsoup-htmlpatcher.md","url":"/plugins/otoroshi-plugins-jsoup-htmlpatcher.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-jwt-jwtuserextractor.md","id":"/plugins/otoroshi-plugins-jwt-jwtuserextractor.md","url":"/plugins/otoroshi-plugins-jwt-jwtuserextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-loggers-bodylogger.md","id":"/plugins/otoroshi-plugins-loggers-bodylogger.md","url":"/plugins/otoroshi-plugins-loggers-bodylogger.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-metrics-prometheusendpoint.md","id":"/plugins/otoroshi-plugins-metrics-prometheusendpoint.md","url":"/plugins/otoroshi-plugins-metrics-prometheusendpoint.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-sink }\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"},{"name":"otoroshi-plugins-metrics-prometheusservicemetrics.md","id":"/plugins/otoroshi-plugins-metrics-prometheusservicemetrics.md","url":"/plugins/otoroshi-plugins-metrics-prometheusservicemetrics.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-metrics-servicemetrics.md","id":"/plugins/otoroshi-plugins-metrics-servicemetrics.md","url":"/plugins/otoroshi-plugins-metrics-servicemetrics.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-mirror-mirroringplugin.md","id":"/plugins/otoroshi-plugins-mirror-mirroringplugin.md","url":"/plugins/otoroshi-plugins-mirror-mirroringplugin.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-oauth1-oauth1callerplugin.md","id":"/plugins/otoroshi-plugins-oauth1-oauth1callerplugin.md","url":"/plugins/otoroshi-plugins-oauth1-oauth1callerplugin.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-oidc-oidcaccesstokenasapikey.md","id":"/plugins/otoroshi-plugins-oidc-oidcaccesstokenasapikey.md","url":"/plugins/otoroshi-plugins-oidc-oidcaccesstokenasapikey.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-oidc-oidcaccesstokenvalidator.md","id":"/plugins/otoroshi-plugins-oidc-oidcaccesstokenvalidator.md","url":"/plugins/otoroshi-plugins-oidc-oidcaccesstokenvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-oidc-oidcheaders.md","id":"/plugins/otoroshi-plugins-oidc-oidcheaders.md","url":"/plugins/otoroshi-plugins-oidc-oidcheaders.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-quotas-instancequotas.md","id":"/plugins/otoroshi-plugins-quotas-instancequotas.md","url":"/plugins/otoroshi-plugins-quotas-instancequotas.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-quotas-servicequotas.md","id":"/plugins/otoroshi-plugins-quotas-servicequotas.md","url":"/plugins/otoroshi-plugins-quotas-servicequotas.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-security-securitytxt.md","id":"/plugins/otoroshi-plugins-security-securitytxt.md","url":"/plugins/otoroshi-plugins-security-securitytxt.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-static-staticresponse.md","id":"/plugins/otoroshi-plugins-static-staticresponse.md","url":"/plugins/otoroshi-plugins-static-staticresponse.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-useragent-useragentextractor.md","id":"/plugins/otoroshi-plugins-useragent-useragentextractor.md","url":"/plugins/otoroshi-plugins-useragent-useragentextractor.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-preroute }\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"},{"name":"otoroshi-plugins-useragent-useragentinfoendpoint.md","id":"/plugins/otoroshi-plugins-useragent-useragentinfoendpoint.md","url":"/plugins/otoroshi-plugins-useragent-useragentinfoendpoint.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-useragent-useragentinfoheader.md","id":"/plugins/otoroshi-plugins-useragent-useragentinfoheader.md","url":"/plugins/otoroshi-plugins-useragent-useragentinfoheader.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-users-hasallowedusersvalidator.md","id":"/plugins/otoroshi-plugins-users-hasallowedusersvalidator.md","url":"/plugins/otoroshi-plugins-users-hasallowedusersvalidator.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-validator }\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"},{"name":"otoroshi-plugins-workflow-workflowendpoint.md","id":"/plugins/otoroshi-plugins-workflow-workflowendpoint.md","url":"/plugins/otoroshi-plugins-workflow-workflowendpoint.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-transformer }\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"},{"name":"otoroshi-plugins-workflow-workflowjob.md","id":"/plugins/otoroshi-plugins-workflow-workflowjob.md","url":"/plugins/otoroshi-plugins-workflow-workflowjob.html","title":"","content":"\n@@@ div { .plugin .plugin-hidden .plugin-kind-job }\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"},{"name":"quickstart.md","id":"/quickstart.md","url":"/quickstart.html","title":"Try Otoroshi in 5 minutes","content":"# Try Otoroshi in 5 minutes\n\nwhat you will need :\n\n* JDK 11\n* curl\n* jq\n* 5 minutes of free time\n\n## The elevator pitch\n\nOtoroshi is an awesome reverse proxy built with Scala that handles all the calls to and between your microservices without service locator and lets you change configuration dynamically at runtime.\n\n## Download otoroshi\n\n```sh\ncurl -L -o otoroshi.jar 'https://github.com/MAIF/otoroshi/releases/download/v1.5.0-rc.2/otoroshi.jar'\n```\n\nIf you don’t/can’t have these tools on your machine, you can start a sandboxed environment using here with the following command\n\n```sh\ndocker run -p \"8080:8080\" maif/otoroshi\n```\n\n## Start otoroshi\n\nto start otoroshi, just run the following command \n\n```sh\njava -jar otoroshi.jar\n```\n\nthis will start an in-memory otoroshi instance with a generated password that will be printed in the logs. You can set the password with the following flags\n\n```sh\njava -Dapp.adminLogin=admin@foo.bar -Dapp.adminPassword=password -jar otoroshi.jar\n```\n\nif you want to have otoroshi content persisted between launch without having to setup a datastore, just usse the following flag\n\n```sh\njava -Dapp.storage=file -jar otoroshi.jar\n```\n\nas the result, you will see something like\n\n```log\n$ java -jar otoroshi.jar\n\n[info] otoroshi-env - Otoroshi version 1.5.0-rc.2\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[warn] otoroshi-env - Scripting is enabled on this Otoroshi instance !\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 / xol1Kwjzqe9OXjqDxxPPbPb9p0BPjhCO\n[info] play.api.Play - Application started (Prod)\n[info] otoroshi-script-manager - Compiling and starting scripts ...\n[info] otoroshi-script-manager - Finding and starting plugins ...\n[info] otoroshi-script-manager - Compiling and starting scripts done in 18 ms.\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-script-manager - Finding and starting plugins done in 4681 ms.\n[info] otoroshi-env - Generating CA certificate for Otoroshi self signed certificates ...\n[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...\n```\n\n## Log into the admin UI\n\njust go to http://otoroshi.oto.tools:8080 and log in with the credentials printed in the logs\n\n## Create you first service\n\nto create your first service you can either do it using the admin UI or using the admin API. Let's use the admin API.\n\nBy default, otoroshi registers an admin apikey with `admin-api-apikey-id:admin-api-apikey-secret` value (those values can be tuned at first startup). Of course you can create your own with\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/apikeys/_template \\\n -u admin-api-apikey-id:admin-api-apikey-secret \\\n -d '{\n \"clientId\": \"quickstart\",\n \"clientSecret\": \"secret\",\n \"clientName\": \"quickstart-apikey\",\n \"authorizedEntities\": [\"group_admin-api-group\"]\n}' | jq\n```\n\nnow let create a new service to proxy `https://maif.gitub.io` on domain `maif.oto.tools`. This service will be public and will not require an apikey to pass\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/_template \\\n -u quickstart:secret \\\n -d '{\n \"name\": \"quickstart-service\", \n \"hosts\": [\"maif.oto.tools\"], \n \"targets\": [{ \"host\": \"maif.github.io\", \"scheme\": \"https\" }], \n \"publicPatterns\": [\"/.*\"]\n}' | jq\n```\n\nnow just go to `http://maif.oto.tools:8080` to check if it works\n\n## Create a service to proxy an api\n\nnow will we proxy the api at `https://aws.random.cat/meow` that returns random cat pictures and make it use apikeys.\n\n```sh\n$ curl https://aws.random.cat/meow | jq\n\n{\n \"file\": \"https://purr.objects-us-east-1.dream.io/i/20161003_163413.jpg\"\n}\n```\n\nFirst let's create the service \n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/_template \\\n -u quickstart:secret \\\n -d '{\n \"id\": \"cats-api\",\n \"name\": \"cats-api\", \n \"hosts\": [\"cats.oto.tools\"], \n \"targets\": [{ \"host\": \"aws.random.cat\", \"scheme\": \"https\" }],\n \"root\": \"/meow\"\n}' | jq\n```\n\nbut if you try to use it, you will have something like :\n\n```sh\n$ curl http://cats.oto.tools:8080 | jq\n\n{\n \"Otoroshi-Error\": \"No ApiKey provided\"\n}\n```\n\nthat's because the api is not public and needs apikeys to access it. So let's create an apikey\n\n```sh\ncurl -X POST -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/apikeys/_template \\\n -u quickstart:secret \\\n -d '{\n \"clientId\": \"apikey1\",\n \"clientSecret\": \"secret\",\n \"clientName\": \"quickstart-apikey-1\",\n \"authorizedEntities\": [\"group_default\"]\n}' | jq\n``` \n\nand try again\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret | jq\n\n{\n \"file\": \"https://purr.objects-us-east-1.dream.io/i/vICG4.gif\"\n}\n```\n\nnow let's try to play with quotas. First, we need to know what is the current state of the apikey quotas by enabling otoroshi headers about consumptions\n\n```sh\ncurl -X PATCH -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/cats-api \\\n -u quickstart:secret \\\n -d '[\n { \"op\": \"replace\", \"path\": \"/sendOtoroshiHeadersBack\", \"value\": true }\n]' | jq\n```\n\nand retry the call with \n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 200 OK\nDate: Tue, 10 Mar 2020 12:56:08 GMT\nServer: Apache\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\nCache-Control: no-cache, must-revalidate\nOtoroshi-Request-Id: 1237361356529729796\nOtoroshi-Proxy-Latency: 79\nOtoroshi-Upstream-Latency: 416\nOtoroshi-Request-Timestamp: 2020-03-10T13:55:11.195+01:00\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET\nOtoroshi-Daily-Calls-Remaining: 9999998\nOtoroshi-Monthly-Calls-Remaining: 9999998\nContent-Type: application/json\nContent-Length: 71\n\n{\"file\":\"https:\\/\\/purr.objects-us-east-1.dream.io\\/i\\/beerandcat.jpg\"}\n```\n\nnow let's try to allow only 10 request per day on the apikey\n\n```sh\ncurl -X PATCH -H 'Content-Type: application/json' \\\n http://otoroshi-api.oto.tools:8080/api/services/cats-api/apikeys/apikey1 \\\n -u quickstart:secret \\\n -d '[\n { \"op\": \"replace\", \"path\": \"/dailyQuota\", \"value\": 10 }\n]' | jq\n```\n\nthen try to call you api again\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 200 OK\nDate: Tue, 10 Mar 2020 13:00:01 GMT\nServer: Apache\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\nCache-Control: no-cache, must-revalidate\nOtoroshi-Request-Id: 1237362334930829633\nOtoroshi-Proxy-Latency: 71\nOtoroshi-Upstream-Latency: 92\nOtoroshi-Request-Timestamp: 2020-03-10T13:59:04.456+01:00\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET\nOtoroshi-Daily-Calls-Remaining: 7\nOtoroshi-Monthly-Calls-Remaining: 9999997\nContent-Type: application/json\nContent-Length: 66\n\n{\"file\":\"https:\\/\\/purr.objects-us-east-1.dream.io\\/i\\/C1XNK.jpg\"}\n```\n\neventually you will get something like\n\n```sh\n$ curl http://cats.oto.tools:8080 -u apikey1:secret --include\n\nHTTP/1.1 429 Too Many Requests\nOtoroshi-Error: true\nOtoroshi-Error-Msg: You performed too much requests\nOtoroshi-State-Resp: --\nDate: Tue, 10 Mar 2020 12:59:11 GMT\nContent-Type: application/json\nContent-Length: 52\n\n{\"Otoroshi-Error\":\"You performed too much requests\"}\n```"},{"name":"admin.md","id":"/setup/admin.md","url":"/setup/admin.html","title":"Manage admin users","content":"# Manage admin users\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated and UI may have changed\n@@@\n\n## Create admin user after the first run\n\nClick on the `Create an admin user` warning popup, or go to `settings (cog icon) / Admins`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou will see the list of registered admin users.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register admin.`\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, enter informations about the new admin you want to create.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register Admin`.\n\n@@@ div { .centered-img }\n\n@@@\n\nNow, you can discard the generated admin, confirm, then logout, login with the admin user you have just created and the danger popup will go away\n\n@@@ div { .centered-img }\n\n@@@\n\n## Create admin user with U2F device login\n\nGo to `settings (cog icon) / Admins`, click on `Register Admin`.\n\n@@@ div { .centered-img }\n\n@@@\n\nEnter informations about the new admin you want to create.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `Register Admin with WebAuthn`.\n\nOtoroshi will ask you to plug your FIDO U2F device and touch it to complete registration.\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ warning\nTo be able to use FIDO U2F devices, Otoroshi must be served over https\n@@@\n\n## Discard admin user\n\nGo to `settings (cog icon) / Admins`, at the bottom of the page, you will see a list of admin users that you can discard. Just click on the `Discard User` button on the right side of the row and confirm that you actually want to discard an admin user.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Admin sessions management\n\nGo to `settings (cog icon) / Admins sessions`, you will see a list of active admin user sessions\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can either discard single sessions one by one using the `Discard Session` on each targeted row of the list or discard all active sessions using the `Discard all sessions` button at the top of the page.\n"},{"name":"dangerzone.md","id":"/setup/dangerzone.md","url":"/setup/dangerzone.html","title":"Configure the Danger zone","content":"# Configure the Danger zone\n\n@@@ warning\nThis section is under rewrite. The following content is deprecated and UI may have changed\n@@@\n\nNow that you have an actual admin account, go to `setting (cog icon) / Danger Zone` in order to configure your Otoroshi instance.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Commons settings\n\nThis part allows you to configure various things :\n\n* `No Auth0 login` => allow you to disabled Auth0 login to the Otoroshi admin dashboard\n* `API read only` => disable `writes` on the Otoroshi admin api\n* `Use HTTP streaming` => use http streaming for each response. It should always be true\n* `Auto link default` => when no group is specified on a service, it will be assigned to default one\n* `Use circuit breakers` => allow usage of circuit breakers for each service\n* `Log analytics on servers` => all analytics will be logged on the servers\n* `Use new http client as the default Http client` => all http call will use the new http client 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` => change the character of endless HTTP responses from `0` to `🖕`\n* `Limit concurrent requests` => allow you to specify a max number of concurrent requests on an Otoroshi instance to avoid overloading\n* `Max concurrent requests` => max allowed number of concurrent requests on an Otoroshi instance to avoid overloading\n* `Max HTTP/1.0 response size` => max size of an HTTP/1.0 responses, because they are memory mapped\n* `Max local events` => number of events stored localy (alerts and audits)\n* `lines` => at least one (`prod`). for other, it will allow you to declare urls like `service.line.domain.tld`. For prod it will be `service.domain.tld`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Whitelist / blacklist settings\n\nOtoroshi is capable of filtering request by ip address, allowing or blocking requests.\n\nOtoroshi also provides a fun feature called `Endless HTTP responses`. If you put an ip address in that field, then, for any http request on Otoroshi, every response will be 128 GB of `0`.\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ note\nNote that you may provide ip address with wildcard like the following `42.42.*.42` or `42.42.42.*` or `42.42.*.*`\n@@@\n\n## Global throttling settings\n\nOtoroshi is capable of managing throttling at a global level. Here you can configure number of authorized requests per second on a single Otoroshi instance and the number of authorized request per second for a unique ip address.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Analytics settings\n\nOne on the major features of Otoroshi is being able of generating internal events. Those events are not stored in Otoroshi's datastore but can be sent using `WebHooks`. You can configure those `WebHooks` from the `Danger Zone`.\n\nOtoroshi is also capable of reading some analytics and displays it from another MAIF product called `Omoïkane`. As Omoikane is not publicly available yet, is capable of storing events in an [Elastic](https://www.elastic.co/) cluster. For more information about analytics and what it does, just go to the @ref:[detailed chapter](../integrations/analytics.md)\n\n## Kafka settings\n\nOne on the major features of Otoroshi is being able of generating internal events. These events are not stored in Otoroshi's datastore but can be sent using a [Kafka message broker](https://kafka.apache.org/). You can configure Kafka access from the `Danger Zone`.\n\nBy default, Otoroshi's alert events will be sent on `otoroshi-alerts` topic, Otoroshi's audit events will be sent on `otoroshi-audits` topic and Otoroshi's traffic events will be sent on `otoroshi-analytics` topic.\n\n@@@ warning\nKeystore and truststore paths are optional local path on the server hosting Otoroshi\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Kafka integration and what it does, just go to the @ref:[detailed chapter](../integrations/analytics.md)\n\n## Alerts settings\n\nEach time a dangerous action or something unusual is performed on Otoroshi, it will create an alert and store it. You can be notified for each of these alerts using `WebHooks` or emails. To do so, just add the `WebHook` URL and optional headers in the `Danger Zone` or any email address you want (you can add more than one email address).\n\nYou can enable mutual authentication via the `Use mTLS` button and add your certificates. The `TLS loose` option will block all untrustful ssl configs, the `TrustAll` option allows any server certificates even the self-signed ones.\n\n@@@ div { .centered-img }\n\n@@@\n\n## StatsD settings\n\nOtoroshi is capable of sending internal metrics to a StatsD agent. Just put the host and port of you StatsD agent in the `Danger Zone` to collect these metrics. If you using [Datadog](https://www.datadoghq.com), don't forget to check the dedicated button :)\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about StatsD integration and what it does, just go to the @ref:[detailed chapter](../integrations/statsd.md)\n\n## Mailer settings\n\nIf you want to send emails for every alert generated by Otoroshi, you need to configure your Mailgun credentials in the `Danger Zone`. These parameters are provided in you Mailgun domain dashboard (i.e. https://app.mailgun.com/app/domains/my.domain.oto.tools) in the information section.\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Mailgun integration and what it does, just go to the @ref:[detailed chapter](../integrations/mailgun.md)\n\n## CleverCloud settings\n\nAs we built our products to run on Clever-Cloud, Otoroshi has a close integration with Clever-Cloud. In this section of `Danger Zone` you can configure how to access Clever-Cloud API.\n\nTo generate the needed value, please refers to [Clever-Cloud documentation](https://www.clever-cloud.com/doc/clever-cloud-apis/cc-api/)\n\n@@@ div { .centered-img }\n\n@@@\n\nFor more information about Clever-Cloud integration and what it does, just go to the @ref:[detailed chapter](../integrations/clevercloud.md)\n\n## Import / exports and panic mode\n\nFor more details about imports and exports, please go to the @ref:[dedicated chapter](../usage/8-importsexports.md)\n\nAbout panic mode, it's an unusual feature that allows you to discard all current admin. sessions, allows only admin users with U2F devices to log back, and pass the API in read-only mode. Only a person who has access to Otoroshi's datastore will be able to turn it back on.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"index.md","id":"/setup/index.md","url":"/setup/index.html","title":"Setup Otoroshi","content":"# Setup Otoroshi\n\nNow that Otoroshi is running, you are ready to log into the Otoroshi admin dashboard and setup your instance. Just go to :\n\nhttp://otoroshi.oto.tools:8080\n\nand you will see the login page\n\n@@@ div { .centered-img }\n\n@@@\n\n@@@ warning\nUse the credentials generated in Otoroshi **logs** during **first run**.\n@@@\n\n@@@ div { .centered-img #first-login-example }\n\n@@@\n\n(of course, you can change this url dependending on the configuration you provided to Otoroshi).\n\nOnce logged in, the first screen you'll see should look like :\n\n@@@ div { .centered-img #first-login }\n\n@@@\n\nAs you can see, Otoroshi is not really happy about you being logged with a generated admin account.\n\nBut we will fix that in the next chapter\n\n@@@ index\n\n* [create admins](./admin.md)\n* [configure danger zone](./dangerzone.md)\n\n@@@\n"},{"name":"clustering.md","id":"/topics/clustering.md","url":"/topics/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"},{"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 topics supported by Otoroshi\n\n@@@ index\n\n* [Chaos engineering with the Snow Monkey](./snow-monkey.md)\n* [JWT Tokens verification](./jwt-verifications.md)\n* [SSL/TLS termination with Otoroshi](./ssl.md)\n* [Mutual TLS with Otoroshi](./mtls.md)\n* [Otoroshi clustering](./clustering.md)\n* [Otoroshi plugins](./plugins.md)\n* [Otoroshi monitoring](./monitoring.md)\n\n@@@\n"},{"name":"jwt-verifications.md","id":"/topics/jwt-verifications.md","url":"/topics/jwt-verifications.html","title":"JWT Tokens verification","content":"# JWT Tokens verification\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. In the Service descriptor page, you can find a `Jwt token Verification` section dedicated to this topic.\n\n## Service descriptor local verifications\n\n@@@ div { .centered-img }\n\n@@@\n\nin this section you can select the type of verification you can choose if the verifier is local to the `Service descriptor` or reference a global one.\n\nYou can also enabled/disable jwt verification and activate strict mode. In strict mode, requests will be rejected if the jwt token is not found.\n\n### Jwt token location\n\nYou can use the `Source` selector to specify where the Jwt token can be found. \n\n* in a query string param\n\n@@@ div { .centered-img }\n\n@@@\n\n* in a header\n\n@@@ div { .centered-img }\n\n@@@\n\n* in a cookie\n\n@@@ div { .centered-img }\n\n@@@\n\n### Jwt signing\n\nYou can use the `Algo.` selector to specify the signing algorithm to use to verifiy the token\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can choose between\n\n* Hmac + SHA256\n* Hmac + SHA384\n* Hmac + SHA512\n* RSA + SHA256\n* RSA + SHA384\n* RSA + SHA512\n* Elliptic Curve + SHA256\n* Elliptic Curve + SHA384\n* Elliptic Curve + SHA512\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can use syntax like `${env.MY_ENV_VAR}` or `${config.my.config.path}` to provide secret/keys values. \n\n\n### Just verify signature and fields value\n\nUsing the `Verif. strategy` selector, you can choose `Verify jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be send to the target just like that.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Re-sign the token\n\nUsing the `Verif. strategy` selector, you can choose `Verify and re-sign jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be re-signed using the settings provided in `Re-sign algo` and will be send to the target.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Transform the token\n\nUsing the `Verif. strategy` selector, you can choose `Verify, re-sign and transform jwt token`. This will verify if the token is signed using the settings from `jwt signing` section and the value of the fields provided in `Verify token fields`. Then the token will be re-signed using the settings provided in `Re-sign algo`. You can also change the location of the token using `Token location`, remove fields using `Remove token fields`, set fields value using `Set token fields` and even rename fields using `Rename token fields`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also use a mini expression language in `Set token fields`. You just have to add expressions in values like `${expression}`. Supported expressions are the following :\n\n* `${date}` => set the current date\n* `${date.format('dd/MM/yyyy')}` => set the current date formatted with the format you want\n* `${token.fieldName}` => get the value of the field named `fieldName`\n* `${token.fieldName.replace('a', 'b')}` => get the value of the field named `fieldName` and replace `a` with `b`\n* `${token.fieldName.replaceAll('[0-9]', '-')}` => get the value of the field named `fieldName` and replace digits with `-`\n\nyou can of course use multiple expressions in one field like `my-value-is-${date}-with${token.user}`\n\n## Global verifications\n\nYou can create global jwt verifiers and reference them in your services (from the `Type` selector). When you set the type of verification to `Reference to a global definition`, you can choose an existing global jwt verifier\n\n@@@ div { .centered-img }\n\n@@@\n\nTo create a global verifier, go to `Settings (cog icon) / Global Jwt Verifiers` and it will display the list of global verifiers.\n\n@@@ div { .centered-img }\n\n@@@\n\nyou can them create, edit or delete verifiers\n\n@@@ div { .centered-img }\n\n@@@\n\n"},{"name":"monitoring.md","id":"/topics/monitoring.md","url":"/topics/monitoring.html","title":"Monitoring Otoroshi","content":"# Monitoring Otoroshi\n\nThe Otoroshi API exposes two endpoints for \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\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 (`app.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 `app.health.accessKey`, `otoroshi.metrics.accessKey` will have the value of `app.health.accessKey`.\n \n## Examples\n\nlet say `app.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":"mtls.md","id":"/topics/mtls.md","url":"/topics/mtls.html","title":"Mutual TLS with Otoroshi","content":"# Mutual TLS with Otoroshi\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```\nplay.server.https.wantClientAuth=true\n# or\n# play.server.https.wantClientNeed=true\notoroshi.ssl.fromOutside.clientAuth=None|Want|Need\n```\n\nor using env. variables\n\n```\nHTTPS_WANT_CLIENT_AUTH=true \n# HTTPS_NEED_CLIENT_AUTH=true \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\n@@@ warning\nThe following section is under rewrite. The following content is deprecated\n@@@\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@@@ note { title=\"Experimental Feature\" }\nDynamic Mutual TLS is an experimental feature. It can change until it becomess an official feature\n@@@\n\n## End-to-end mTLS\n\nThe use case is the following :\n\n@@@ div { .centered-img }\n\n@@@\n\nfor this demo you will have to edit your `/etc/hosts` file to add the following entries\n\n```\n127.0.0.1 api.backend.lol api.frontend.lol www.backend.lol www.frontend.lol validation.backend.lol\n```\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.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.backend.lol.key -out ./server/_.backend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.backend.lol.key -sha256 -out ./server/_.backend.lol.csr -subj \"/CN=*.backend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.backend.lol.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.lol.cer\n# verify the certificate, should output './server/_.backend.lol.cer: OK'\nopenssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.lol.cer\n\n\n# now create the frontend cert key, use password as pass phrase\nopenssl genrsa -out ./server/_.frontend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./server/_.frontend.lol.key -out ./server/_.frontend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./server/_.frontend.lol.key -sha256 -out ./server/_.frontend.lol.csr -subj \"/CN=*.frontend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./server/_.frontend.lol.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.lol.cer\n# verify the certificate, should output './server/_.frontend.lol.cer: OK'\nopenssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.lol.cer\n\n\n# now create the client cert key for backend, use password as pass phrase\nopenssl genrsa -out ./client/_.backend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.backend.lol.key -out ./client/_.backend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.backend.lol.key -out ./client/_.backend.lol.csr -subj \"/CN=*.backend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.backend.lol.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.lol.cer\n# generate a pkcs12 version of the cert and key, use password as password\nopenssl pkcs12 -export -clcerts -in client/_.backend.lol.cer -inkey client/_.backend.lol.key -out client/_.backend.lol.p12\n\n\n# now create the client cert key for frontend, use password as pass phrase\nopenssl genrsa -out ./client/_.frontend.lol.key 2048\n# remove pass phrase\nopenssl rsa -in ./client/_.frontend.lol.key -out ./client/_.frontend.lol.key\n# generate the csr for the certificate\nopenssl req -new -key ./client/_.frontend.lol.key -out ./client/_.frontend.lol.csr -subj \"/CN=*.frontend.lol\"\n# generate the certificate\nopenssl x509 -req -days 365 -sha256 -in ./client/_.frontend.lol.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.lol.cer\n# generate a pkcs12 version of the cert and key, use password as password\nopenssl pkcs12 -export -clcerts -in client/_.frontend.lol.cer -inkey client/_.frontend.lol.key -out client/_.frontend.lol.p12\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.lol.cer\n│   ├── _.backend.lol.csr\n│   ├── _.backend.lol.key\n│   ├── _.backend.lol.p12\n│   ├── _.frontend.lol.cer\n│   ├── _.frontend.lol.csr\n│   ├── _.frontend.lol.key\n│   └── _.frontend.lol.p12\n└── server\n ├── _.backend.lol.cer\n ├── _.backend.lol.csr\n ├── _.backend.lol.key\n ├── _.frontend.lol.cer\n ├── _.frontend.lol.csr\n └── _.frontend.lol.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.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n}; \n\nhttps.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```\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.lol:8444/\n# will print {\"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.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nhttps.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```\n\nyou can test your new server with\n\n```sh\ncurl --cacert ./ca/ca-backend.cer --cert-type pkcs12 --cert ./client/_.backend.lol.p12:password https://api.backend.lol:8444/\n# will print {\"message\":\"Hello World!\"}\n```\n\n### Otoroshi setup\n\nDownload the latest version of the Otoroshi jar and run it like\n\n```sh\njava -jar 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 / xxxxxxxxxxxx\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 / xxxxxxxxxxxx` displayed in the logs. Once logged in, create a new public service exposed on `http://api.frontend.lol` that targets `ahttps://api.backend.lol:8444/`.\n\n@@@ div { .centered-img }\n\n@@@\n\nand test it\n\n```sh\ncurl http://api.frontend.lol:8080/\n# the following error should be returned: {\"Otoroshi-Error\":\"Something went wrong, you should try later. Thanks for your understanding.\"}\n```\n\n@@@ warning\nAs seen before, the target of the otoroshi service is `ahttps://api.backend.lol:8444/`. `ahttps://` is not a typo and is intended. This tells otoroshi to use its experimental `http client` with dynamic tls support to fetch this resource.\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.lol` 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.lol.cer` and `./client/_.backend.lol.key` respectively in `Certificate full chain` and `Certificate private key`.\n\n@@@ div { .centered-img }\n\n@@@\n\nand retry the following curl command \n\n```sh\ncurl http://api.frontend.lol:8080/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\nnow we have to expose `https://api.frontend.lol: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.lol.cer` and `./server/_.frontend.lol.key` respectively in `Certificate full chain` and `Certificate private key`.\n\nand try the following command\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer https://api.frontend.lol:8443/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\nnow we have to enforce the fact that we want client certificate for `api.frontend.lol`. To do that, we have to create a `Validation authority` in otoroshi and use it on the `api.frontend.lol` service. Go to http://otoroshi.oto.tools:8080/bo/dashboard/validation-authorities and create a new item. A validation authority is supposed to be a remote service that will say if the client certificate is valid. Here we don't really care if the certificate is valid or not, but we want to enforce the fact that there is a client certificate. So just check the `All cert. valid button`.\n\n@@@ div { .centered-img }\n\n@@@\n\nnow go back on your `api.frontend.lol` service, in the `Validation authority` section and select the authority you just created.\n\n@@@ div { .centered-img }\n\n@@@\n\nnow if you retry \n\n```sh\ncurl --cacert ./ca/ca-frontend.cer https://api.frontend.lol:8443/\n# the output should be: {\"Otoroshi-Error\":\"You're not authorized here !\"}\n```\n\nyou should get an error because no client cert. is passed with the request. But if you pass the `./client/_.frontend.lol.p12` client cert in your curl call\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/_.frontend.lol.p12:password https://api.frontend.lol:8443/\n# the output should be: {\"message\":\"Hello World!\"}\n```\n\n### End to end test\n\nNow we can try to write a small nodejs client that uses our client certificates. Create a `client.js` file with the following code\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \n\nprocess.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;\n\nconst options = { \n hostname: 'api.frontend.lol', \n port: 8443, \n path: '/', \n method: 'GET', \n key: fs.readFileSync('./client/_.frontend.lol.key'), \n cert: fs.readFileSync('./client/_.frontend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-frontend.cer'), \n}; \n\nconst req = https.request(options, (res) => { \n console.log('statusCode', res.statusCode);\n console.log('headers', res.headers);\n console.log('body:');\n res.on('data', (data) => { \n process.stdout.write(data); \n }); \n}); \n\nreq.end(); \n\nreq.on('error', (e) => { \n console.error(e); \n});\n```\n\nand run the following command\n\n```sh\n$ node client.js\n# statusCode 200\n# headers { date: 'Mon, 10 Dec 2018 16:01:11 GMT',\n# connection: 'close',\n# 'transfer-encoding': 'chunked',\n# 'content-type': 'application/json' }\n# body:\n# {\"message\":\"Hello World!\"}\n```\n\nAnd that's it \n\n## Validating client certificates based on user identity\n\n@@@ note { title=\"Experimental Feature\" }\nValidation authorities is an experimental feature. It can change until it becomess an official feature\n@@@\n\nThe use case is the following :\n\n@@@ div { .centered-img }\n\n@@@\n\nthe idea here is to provide a unique client certificate per device that can access Otoroshi and use a validation authority to check if the user is allowed to access the underlying app with a specific device.\n\n### Generate client certificates for devices\n\nTo do that we are going to create two client certificates, one per device (let say for a laptop and a desktop computer). We are going to use the device serial number as common name of the certificate to be able to identify the device behind the certificate.\n\n```sh\nopenssl genrsa -out ./client/device-1.key 2048\nopenssl rsa -in ./client/device-1.key -out ./client/device-1.key\nopenssl req -new -key ./client/device-1.key -out ./client/device-1.csr -subj \"/CN=mbp-123456789\"\nopenssl x509 -req -days 365 -sha256 -in ./client/device-1.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 3 -out ./client/device-1\nopenssl pkcs12 -export -clcerts -in client/device-1 -inkey client/device-1.key -out client/device-1.p12\n\nopenssl genrsa -out ./client/device-2.key 2048\nopenssl rsa -in ./client/device-2.key -out ./client/device-2.key\nopenssl req -new -key ./client/device-2.key -out ./client/device-2.csr -subj \"/CN=nuc-987654321\"\nopenssl x509 -req -days 365 -sha256 -in ./client/device-2.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 4 -out ./client/device-2\nopenssl pkcs12 -export -clcerts -in client/device-2 -inkey client/device-2.key -out client/device-2.p12\n```\n\n### Setup actual validation\n\nnow we are going to write an validation authority (with mTLS too) that is going to respond on `https://validation.backend.lol:8445`. The server has access to a list of apps, users and devices to check if everything is correct. In this implementation, the lists are hardcoded, but you can write your own implementation that will fetch data from your corporate LDAP, CA, etc. Create a `validation.js` file and add the following content. Don't forget to do `yarn add x509` before running the server with `node validation.js`\n\n```js\nconst fs = require('fs'); \nconst https = require('https'); \nconst x509 = require('x509');\n\n// list of knwon apps\nconst apps = [\n {\n \"id\": \"iogOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"name\": \"my-web-service\",\n \"description\": \"A service that says hello\",\n \"host\": \"www.frontend.lol\"\n }\n];\n\n// list of known users\nconst users = [\n {\n \"name\": \"Mathieu\",\n \"email\": \"mathieu@oto.tools\",\n \"appRights\": [\n {\n \"id\": \"iogOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"profile\": \"user\",\n \"forbidden\": false\n },\n {\n \"id\": \"PqgOIDH09EktFhydTp8xspGvdaBq961DUDr6MBBNwHO2EiBMlOdafGnImhbRGy8z\",\n \"profile\": \"none\",\n \"forbidden\": true\n },\n ],\n \"ownedDevices\": [\n \"mbp-123456789\",\n \"nuc-987654321\",\n ]\n }\n];\n\n// list of known devices\nconst devices = [\n {\n \"serialNumber\": \"mbp-123456789\",\n \"hardware\": \"Macbook Pro 2018 13 inc. with TouchBar, 2.6 GHz, 16 Gb\",\n \"acquiredAt\": \"2018-10-01\",\n },\n {\n \"serialNumber\": \"nuc-987654321\",\n \"hardware\": \"Intel NUC i7 3.0 GHz, 32 Gb\",\n \"acquiredAt\": \"2018-09-01\",\n },\n {\n \"serialNumber\": \"iphone-1234\",\n \"hardware\": \"Iphone XS, 256 Gb\",\n \"acquiredAt\": \"2018-12-01\",\n }\n];\n\nconst options = { \n key: fs.readFileSync('./server/_.backend.lol.key'), \n cert: fs.readFileSync('./server/_.backend.lol.cer'), \n ca: fs.readFileSync('./ca/ca-backend.cer'), \n requestCert: true, \n rejectUnauthorized: true\n}; \n\nfunction readBody(request) {\n return new Promise((success, failure) => {\n const body = [];\n request.on('data', (chunk) => {\n body.push(chunk);\n }).on('end', () => {\n const bodyStr = Buffer.concat(body).toString();\n success(JSON.parse(bodyStr));\n });\n });\n}\n\nfunction chainIsValid(chain) {\n // validate cert dates\n // validate cert against clr\n // validate whatever you want here\n return true;\n}\n\nfunction call(req, res) {\n readBody(req).then(body => {\n const service = body.service;\n const email = (body.user || { email: 'mathieu@oto.tools' }).email; // here, should not be null if used with an otoroshi auth. module\n // common name should be device serial number\n const commonName = x509.getSubject(body.chain).commonName\n // search for a known device\n const device = devices.filter(d => d.serialNumber === commonName)[0];\n // search for a known user\n const user = users.filter(d => d.email === email)[0];\n // search for a known application\n const app = apps.filter(d => d.id === service.id)[0];\n res.writeHead(200, { 'Content-Type': 'application/json' }); \n if (chainIsValid(body.chain.map(x509.parseCert)) && user && device && app) {\n // check if the user actually owns the device\n const userOwnsDevice = user.ownedDevices.filter(d => d === device.serialNumber)[0];\n // check if the user has rights to access the app\n const rights = user.appRights.filter(d => d.id === app.id)[0];\n const hasRightToUseApp = !rights.forbidden\n if (userOwnsDevice && hasRightToUseApp) {\n // yeah !!!!\n console.log(`Call from user \"${user.email}\" with device \"${device.hardware}\" on app \"${app.name}\" with profile \"${rights.profile}\" authorized`)\n res.end(JSON.stringify({ status: 'good', profile: rights.profile }) + \"\\n\"); \n } else {\n // nope !!! nope, nope nope\n console.log(`Call from user \"${user.email}\" with device \"${device.hardware}\" on app \"${app.name}\" unauthorized because user doesn't owns the hardware or has no rights`)\n res.end(JSON.stringify({ status: 'unauthorized' }) + \"\\n\"); \n }\n } else {\n console.log(`Call unauthorized`)\n res.end(JSON.stringify({ status: 'unauthorized' }) + \"\\n\"); \n }\n });\n}\n\nhttps.createServer(options, call).listen(8445);\n```\n\nthe corresponding authority validation can be created in Otoroshi like \n\n```json\n{\n \"id\": \"r7m8j31rh66hhdia3ormfm0wfevu1kvg0zgaxsp3oxb6ivf7fy8kvygmvnrlxv81\",\n \"name\": \"Actual validation authority\",\n \"description\": \"Actual validation authority\",\n \"url\": \"ahttps://validation.backend.lol:8445\",\n \"host\": \"validation.backend.lol\",\n \"goodTtl\": 600000,\n \"badTtl\": 60000,\n \"method\": \"POST\",\n \"path\": \"/certificates/_validate\",\n \"timeout\": 10000,\n \"noCache\": false,\n \"alwaysValid\": false,\n \"headers\": {}\n}\n```\n\nbut you don't need to create it right now.\n\nTypically, a validation authority server is a server with a route on `POST /certificates/_validate` that accepts `application/json` and returns `application/json` with a body like\n\n```json\n{\n \"apikey\": nullable {\n \"clientId\": String,\n \"clientName\": String,\n \"authorizedEntities\": Seq[String],\n \"enabled\": Boolean,\n \"readOnly\": Boolean,\n \"allowClientIdOnly\": Boolean,\n \"throttlingQuota\": Long,\n \"dailyQuota\": Long,\n \"monthlyQuota\": Long,\n \"metadata\": Map[String, String]\n },\n \"user\": nullable {\n \"email\": String,\n \"name\": String,\n },\n \"service\": {\n \"id\": String,\n \"name\": String,\n \"groups\": Seq[String],\n \"domain\": String,\n \"env\": String,\n \"subdomain\": String,\n \"root\": String,\n \"metadata\": String\n },\n \"chain\": PemFormattedCertificateChainString,\n \"fingerprints\": Array[String]\n}\n```\n\n\n### Setup Otoroshi\n\nYou can start Otoroshi and import data from the `state.json` file in the demo folder. The login tuple is `admin@otoroshi.io / password`. The `state.json` file contains everything you need for the demo, like certificates, service descriptors, auth. modules, etc ...\n\n```sh\njava -Dapp.importFrom=$(pwd)/state.json -Dapp.privateapps.port=8080 -jar 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 - Importing from: /pwd/state.json\n[info] play.api.Play - Application started (Prod)\n[info] otoroshi-env - Successful import !\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```\n\n### Testing \n\nYou can test the service with curl like\n\n```sh\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/device-1.p12:password https://www.frontend.lol:8443/\n# output:

Hello World !!!

\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/device-2.p12:password https://www.frontend.lol:8443/\n# output:

Hello World !!!

\ncurl --cacert ./ca/ca-frontend.cer --cert-type pkcs12 --cert ./client/_.frontend.lol.p12:password https://www.frontend.lol:8443/\n# output: {\"Otoroshi-Error\":\"You're not authorized here !\"}\n```\n\nas expected, the first two call works as their common name is known by the validation server. The last one fails as it's not known.\n\n### Validate user identity\n\nNow let's try to setup firefox to provide the client certificate. Open firefox settings, go to `privacy settings and security` and click on `display certificates` at the bottom of the page. Here you can add the frontend CA (`./ca/ca-frontend.cer`) in the `Authorities` tab, check the 'authorize this CA to identify websites', and then in the `certificates` tab, import one of the devices `.p12` file (like `./client/device-1.p12`). Firefox will ask for the files password (it should be `password`).\n\n@@@ div { .centered-img }\n\n@@@\n\nNow restart firefox.\n\nNext, go to the `my-web-service` service in otoroshi (log in with `admin@otoroshi.io / password`) and activate `Enforce user login` in the Authentication section. It means that now, you'll have to log in when you'll go to https://www.frontend.lol:8443. With authentication activated on otoroshi, the user identity will be sent to the validation authority, so you can change the following line in the file `validation.js`\n\n```js\nconst email = (body.user || { email: 'mathieu@oto.tools' }).email; // here, should not be null if used with an otoroshi auth. module\n```\n\nto\n\n```js\nconst email = body.user.email;\n```\n\nThen, in Firefox, go to https://www.frontend.lol:8443/, firefox will ask which client certificate to use. Select the one you imported (in the process, maybe firefox will warn you that the certificate of the site is auto signed, just ignore it and continue ;) )\n\n@@@ div { .centered-img }\n\n@@@\n\nthen, you'll see a login screen from otoroshi. You can log in with `mathieu@oto.tools / password` and then you should see the hello world message.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Going further with user authentication\n\nFor stronger user authentication, you can try to use an auth. module baked by a keycloak instance with yubikey as a strong second factor authentication instead of the basic auth. module we used previously in this article.\n"},{"name":"plugins.md","id":"/topics/plugins.md","url":"/topics/plugins.html","title":"Otoroshi plugins","content":"# Otoroshi 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\n\n* `request sinks` plugins: used when no services are matched in otoroshi. Can reply with any content\n* `pre-routes` plugins: used to extract values (like custom apikeys) and provide them to other plugins or otoroshi engine\n* `access validation` plugins: used to validate if a request can pass or not based on whatever you want\n* `request transformer` plugins: used to transform request, responses and their body. Can be used to return arbitrary content\n* `event listener` plugins: any plugin type can listen to otoroshi internal events and react to thems\n* `job` plugins: tasks taht can run automatically once, on be scheduled with a cron expression or every defined interval\n\n## Code and signatures\n\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/requestsink.scala#L11-L16\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/routing.scala#L60-L63\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/accessvalidator.scala#L63-L82\n* https://github.com/MAIF/otoroshi/blob/master/otoroshi/app/script/script.scala#L314-L455\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#L74-L81\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.6.x/api/scala/index.html#package\n* https://www.playframework.com/documentation/2.6.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\nA lot of plugins comes with otoroshi, you can find it 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"},{"name":"snow-monkey.md","id":"/topics/snow-monkey.md","url":"/topics/snow-monkey.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":"ssl.md","id":"/topics/ssl.md","url":"/topics/ssl.html","title":"SSL/TLS termination with Otoroshi","content":"# SSL/TLS termination with Otoroshi\n\nOtoroshi can be used as an SSL/TLS termination. It is enabled by default but you can customise HTTPS port with `https.port` config. and env. var `HTTPS_PORT`. You can create upload any certificate you want in the Otoroshi UI or using the API. Just go to `settings (cog icon) / SSL/TLSS certificates`.\n\n@@@ note { title=\"Experimental Feature\" }\nDynamic SSL/TLS termination is an experimental feature. It can change until it becomess an official feature\n@@@\n\n@@@ note { title=\"TLS 1.3 support\" }\nOtoroshi does support TLS 1.3 when used in combination with JDK 11\n\n\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n\nHere 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 with no password on the private key.\n\nYou can remove the password of a key with the following command\n\n```sh\nopenssl rsa -in keywithpassword.key -out keywithoutpassword.key\n```\n\n@@@ div { .centered-img }\n\n@@@\n\n"},{"name":"1-groups.md","id":"/usage/1-groups.md","url":"/usage/1-groups.html","title":"Managing service groups","content":"# Managing service groups\n\nGo to `settings (cog icon) / All service groups` to access the list of service groups.\n\n@@@ div { .centered-img }\n\n@@@\n\nAnd you should see the list of existing `Service groups`.\n\n@@@ div { .centered-img }\n\n@@@\n\nBut what is a `Service group` anyway ?\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi :\n\n* **service groups**\n* service descriptors\n* api keys\n\n@@@ div { .centered-img }\n\n@@@\n\nA `service group` is just some kind of logical container for `service descriptors`. A `service group` also has some `api keys` assigned that will be used to access all the `service descriptors` contained in the `service group`.\n\n## Create a service group\n\nA `service group` is a really simple structure with an `id`, a name and a description. To create a new one, just click on the `Add item` button.\n\n@@@ div { .centered-img }\n\n@@@\n\nmodify the name and the description of the group\n\n@@@ div { .centered-img }\n\n@@@\n\nand click on `Create group`\n\n@@@ div { .centered-img }\n\n@@@\n\nThen, you should find your brand new `Service group` in the list of `Service groups`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Update a service\n\nTo update a `Service group`, just click on the edit button of your `Service group`\n\n@@@ div { .centered-img }\n\n@@@\n\nUpdate the name and description of the `Service group` and click on the `Update group` button to validate name update.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Delete a service group\n\nTo delete a `Service group`, just click on the delete button of your `Service group`\n\n@@@ div { .centered-img }\n\n@@@\n\nFinally confirm the command\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"2-services.md","id":"/usage/2-services.md","url":"/usage/2-services.html","title":"Managing services","content":"# Managing services\n\nNow let's create services. 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.\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi\n\n* service groups\n* **service descriptors**\n* api keys\n\n@@@ div { .centered-img }\n\n@@@\n\nA `service descriptor` is contained in one or multiple `service group`s and is allowed to be accessed by all the `api key`s authorized on those `service group`s or apikeys directly authorized on the service itself.\n\n## Create a service descriptor\n\nTo create a `service descriptor`, click on `Add service` on the Otoroshi sidebar. Then you will be asked to choose a name for the service and the group of the service. You also have two buttons to create a new group and assign it to the service and create a new group with a name based on the service name.\n\nYou will have a serie of toggle buttons to\n\n* activate / deactivate a service\n* display maintenance page for a service\n* display contruction page for a service\n* enable otoroshi custom response headers containing request id, latency, etc \n* force https usage on the exposed service\n* enable read only flag : this service will only be used with `HEAD`, `OPTIONS` and `GET` http verbs. You can also active the same flag on `ApiKey`s to be more specific on who cannot use write http verbs.\n\nThen, you will be able to choose the URL that will be used to reach your new service on Otoroshi.\n\n@@@ div { .centered-img #service-flags }\n\n@@@\n\nIn the `service targets` section, you will be able to choose where the call will be forwarded. You can use multiple targets, in that case, Otoroshi will perform a round robin load balancing between the targets. If the `override Host header` toggle is on, the host header will be changed for the host of the target. For example, if you request `http://www.oto.tools/api` with a target to `http://www-internal.service.local/api`, the target will receive a `Host: www-internal.service.local` instead of `Host: www.oto.tools`.\n\nYou can also specify a target root, if you say that the target root is `/foo/`, then any call to `https://my.api.foo` will call `http://192.168.0.42/foo/` and nay call to `https://my.api.foo/bar` will call `http://192.168.0.42/foo/bar`.\n\nIn the URL patterns section, you will be able to choose, URL by URL which is private and which is public. By default, all services are private and each call must provide an `api key`. But sometimes, you need to access a service publicly. In that case, you can provide patterns (regex) to make some or all URL public (for example with the pattern `/.*`). You also have a `private pattern` field to restrict public patterns.\n\n@@@ div { .centered-img #targets }\n\n@@@\n\n### Otoroshi exchange protocol\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 `app.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\n\n### Canary mode\n\nOtoroshi provides a feature called `Canary mode`. It lets you define new targets for a service, and route a percentage of the traffic on those targets. It's a good way to test a new version of a service before public release. As any client need to be routed to the same version of targets any time, Otoroshi will issue a special header and a cookie containing a `session id`. The header is named `Otoroshi-Canary-Id`.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service health check\n\nOtoroshi is also capable of checking the health of a service. You can define a URL that will be tested, and Otoroshi will ping that URL regularly. Will doing so, Otoroshi will pass a numeric value in a header named `Otoroshi-Health-Check-Logic-Test`. You can respond with a header named `Otoroshi-Health-Check-Logic-Test-Result` that contains the value of `Otoroshi-Health-Check-Logic-Test` + 42 to indicate that the service is working properly.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service circuit breaker\n\nIn Otoroshi, each service has its own client settings with a circuit breaker and some retry capabilities. In the `Client settings` section, you will be able to customize the client's behavior.\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service settings\n\nYou can also provide some additionnal information about a given service, like an `Open API` descriptor, some metadata, a list of whitelisted/blacklisted ip addresses, etc.\n\n@@@ div { .centered-img #service-meta }\n\n@@@\n\n### HTTP Headers\n\nHere you can define some headers that will be added to each request to client requests or responses. \nYou will also be able to define headers to route the call only if the defined header is present on the request.\n\n@@@ div { .centered-img #service-meta }\n\n@@@\n\n### CORS \n\nIf you enabled this section, CORS will be automatically supported on the current service provider. The pre-flight request will be handled by Otoroshi. You can customize every CORS headers :\n\n@@@ div { .centered-img }\n\n@@@\n\n### Service authentication\n\nSee @ref:[Aauthentication](./9-auth.md)\n\n### Custom error templates\n\nFinally, you can define custom error templates that will be displayed when an error occurs when Otoroshi try to reach the target or when Otoroshi itself has an error. You can also define custom templates for maintenance and service pages.\n"},{"name":"3-apikeys.md","id":"/usage/3-apikeys.md","url":"/usage/3-apikeys.html","title":"Managing API keys","content":"# Managing API keys\n\nNow that you know how to create service groups and service descriptors, we will see how to create API keys.\n\n## Otoroshi entities\n\nThere are 3 major entities at the core of Otoroshi.\n\n* service groups\n* service descriptors\n* **api keys**\n\n@@@ div { .centered-img }\n\n@@@\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 group`s/`service descriptor`s.\n\nIn the Otoroshi admin dashboard, we chose to access `API keys` from `service descriptors` only, but when you access `API keys` for a `service descriptor`, you actually access `API keys` for the `service group` containing the `service descriptor`.\n\n`API keys` can be provided to Otoroshi through :\n\n* `Otoroshi-Authorization: Basic $base64(client_id:client_secret)` header, in that case, the `Otoroshi-Authorization` header will **not** be sent to the target. `Basic ` is optional.\n* `Authorization: Basic $base64(client_id:client_secret)` header, in that case, the `Authorization` header **will** be sent to the target\n* `Otoroshi-Token: Bearer $jwt_token` where the JWT token has been signed with the `API key` client secret, in that case, the `Otoroshi-Token` header will **not** be sent to the target. `Bearer ` is optional.\n* `Authorization: Bearer $jwt_token` where the JWT token has been signed with the `API key` client secret, in that case, the `Authorization` header **will** be sent to the target\n* `Cookie: access_token=$jwt_token;` where the JWT token has been signed with the `API key` client secret, in that case, the cookie named `access_token` **will** be sent to the target\n* `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers, in that case the `Otoroshi-Client-Id` and `Otoroshi-Client-Secret` headers will not be sent to the target.\n\n## List API keys for a service descriptor\n\nGo to a service descriptor using `All services` quick link in the sidebar or the search box.\n\n@@@ div { .centered-img }\n\n@@@\n\nSelect a `service descriptor`.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on `API keys` in the sidebar\n\n@@@ div { .centered-img }\n\n@@@\n\nYou should see the list of API keys for that `service descriptor`\n\n@@@ div { .centered-img }\n\n@@@\n\n## Create an API key for a service descriptor\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can add a name for your new API key, you can also change client's id and client's secret. You can also configure the throttling rate of the API key (calls per second), and the authorized number of call per day and per month. You may also activate or de-activate the api key from that screen.\n\nInformations about current quotas usage will be returned in response headers.\n\n* `Otoroshi-Daily-Calls-Remaining` : authorized calls remaining for this day\n* `Otoroshi-Monthly-Calls-Remaining` : authorized calls remaining for this month\n* `Otoroshi-Proxy-Latency` : latency induced by Otoroshi\n* `Otoroshi-Upstream-Latency` : latency between Otoroshi and target\n\n@@@ div { .centered-img #quotas }\n\n@@@\n\n@@@ warning\nDaily and monthly quotas are based on the following rules :\n\n* daily quota is computed between 00h00:00.000 and 23h59:59.999\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## Update an API key\n\nTo update an `API key`, just click on the edit button of your `API key`\n\n@@@ div { .centered-img }\n\n@@@\n\nUpdate the name, secret, state and quotas (if needed) of the `API key` and click on the `Update API key` button\n\n@@@ div { .centered-img }\n\n@@@\n\n## Delete an API key\n\nTo delete an `API key`, just click on the delete button of your `API key`\n\n@@@ div { .centered-img }\n\n@@@\n\nand confirm the command\n\n@@@ div { .centered-img }\n\n@@@\n\n### Read only\n\nThe read only flag on an `ApiKey` this apikey can only use allowed services with `HEAD`, `OPTIONS` and `GET` http verbs.\n\n## Use a JWT token to pass an API key\n\nYou can use a JWT token to pass an API key to Otoroshi. \nYou can use `Otoroshi-Authorization: Bearer $jwt_token`, `Authorization: Bearer $jwt_token` header and `Cookie: access_token=$jwt_token;` to pass the JWT token.\nYou have to create a JWT token with a signing algorythm that can be `HS256` or `HS512`. Then you have to provide an `iss` claim with the value of your API key `clientId` and sign the JWT token with your API key `clientSecret`.\n\nFor example, with an API key like `clientId=abcdef` and `clientSecret=1234456789`, your JWT token should look like\n\n```json\n{\n \"alg\": \"HS256\",\n \"typ\": \"JWT\"\n}\n{\n \"iss\":\"abcdef\",\n \"name\": \"John Doe\",\n \"admin\": true\n}\n```\n\nin that case, when you sign the token with the secret of the API key `1234456789`, the signature will be `_eancnYCD3makSSox2v2xErjNYkRtcX558QiJGCbino`, resulting in a encoded JWT header like\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\neyJpc3MiOiJhYmNkZWYiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZX0.\n_eancnYCD3makSSox2v2xErjNYkRtcX558QiJGCbino\n```\n"},{"name":"4-monitor.md","id":"/usage/4-monitor.md","url":"/usage/4-monitor.html","title":"Monitoring services","content":"# Monitoring services\n\nOnce you have declared services, you can monitor them with Otoroshi.\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi\n@@@\n\nOnce you have setup @ref:[Otoroshi events push to an elastic cluster](../integrations/analytics.md) (through webhooks, kafka, or elastic integration) you can setup Otoroshi events read from an elastic cluster. Go to `settings (cog icon) / Danger Zone` and expand the `Analytics: Elastic cluster (write)` 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"},{"name":"5-sessions.md","id":"/usage/5-sessions.md","url":"/usage/5-sessions.html","title":"Managing sessions","content":"# Managing sessions\n\nWith Otoroshi you can manage sessions of connected users and you can discard sessions whenever you want. Session last 24h by default and you can customize them with `app.backoffice.session.exp` and `app.privateapps.session.exp` @ref:[config keys](../firstrun/configfile.md)\n\n## Admin. sessions\n\nTo see last current admin session on Otoroshi from the UI, go to `settings (cog icon) / Admins sessions`. Here you can discard individual sessions or all sessions at once using `Discard session` and `Discard all sessions` buttons.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Private apps. session\n\nTo see last current admin session on Otoroshi from the UI, go to `settings (cog icon) / Priv. apps sessions`. Here you can discard individual sessions or all sessions at once using `Discard session` and `Discard all sessions` buttons.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"6-audit.md","id":"/usage/6-audit.md","url":"/usage/6-audit.html","title":"Auditing Otoroshi","content":"# Auditing Otoroshi\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 `app.events.maxSize` @ref:[config key](../firstrun/configfile.md)). 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\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi. See @ref:[Elastic setup section](../integrations/analytics.md)\n@@@\n\n## Audit trail\n\nTo see last `app.events.maxSize` admin actions on Otoroshi from the UI, go to `settings (cog icon) / Audit log`.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Alerts\n\nTo see last `app.events.maxSize` alerts on Otoroshi from the UI, go to `settings (cog icon) / Alerts log`.\n\n@@@ div { .centered-img }\n\n@@@\n\nYou can also have a look at the payload sent to the Otoroshi server by clicking the `content` button\n\n@@@ div { .centered-img }\n\n@@@\n\n## List of possible alerts\n\n```\nMaxConcurrentRequestReachedAlert\nCircuitBreakerOpenedAlert\nCircuitBreakerClosedAlert\nSessionDiscardedAlert\nSessionsDiscardedAlert\nPanicModeAlert\nOtoroshiExportAlert\nU2FAdminDeletedAlert\nBlackListedBackOfficeUserAlert\nAdminLoggedInAlert\nAdminFirstLogin\nAdminLoggedOutAlert\nDbResetAlert\nDangerZoneAccessAlert\nGlobalConfigModification\nRevokedApiKeyUsageAlert\nServiceGroupCreatedAlert\nServiceGroupUpdatedAlert\nServiceGroupDeletedAlert\nServiceCreatedAlert\nServiceUpdatedAlert\nServiceDeletedAlert\nApiKeyCreatedAlert\nApiKeyUpdatedAlert\nApiKeyDeletedAlert\n```\n"},{"name":"7-metrics.md","id":"/usage/7-metrics.md","url":"/usage/7-metrics.html","title":"Otoroshi global metrics","content":"# Otoroshi global metrics\n\nOtoroshi provide some global metrics about services usage. Go to `settings (cog icon) / Global Ananlytics`\n\n@@@ warning\nYou have to use [Elastic](https://www.elastic.co) to enable analytics features in Otoroshi. See @ref:[Elastic setup section](../integrations/analytics.md)\n@@@\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"8-importsexports.md","id":"/usage/8-importsexports.md","url":"/usage/8-importsexports.html","title":"Import and export","content":"# Import and export\n\nWith Otoroshi you can easily save the current state of the proxy and restore it later. Go to `settings (cog icon) / Danger Zone` and scroll to the bottom of the page\n\n## Full export\n\nClick on the `Full export` button.\n\n@@@ div { .centered-img }\n\n@@@\n\nYour browser will start to download a JSON file containing the internal state of your Otoroshi cluster.\n\n@@@ div { .centered-img }\n\n@@@\n\n## Full import\n\nIf you want to restore an export, go to `settings (cog icon) / Danger Zone` and scroll to the bottom of the page. Click on the `Recover from full export file` button\n\n@@@ div { .centered-img }\n\n@@@\n\nChoose export file on your system.\n\n@@@ div { .centered-img }\n\n@@@\n\nClick on the `Flush datastore and import ...` button, confirm and you will be logged out.\n\n@@@ div { .centered-img }\n\n@@@\n"},{"name":"9-auth.md","id":"/usage/9-auth.md","url":"/usage/9-auth.html","title":"Authentication","content":"# Authentication\n\nYou can create auth. configuration in Otoroshi. Just go to `settings (cog icon) / Authentication configs`.\n\n## OAuth 2\n\nCreate a new `Generic oauth2 provider` config and customize the following informations:\n\n```json\n{\n \"clientId\": \"xxxx\",\n \"clientSecret\": \"xxxx\",\n \"authorizeUrl\": \"http://yourOAuthServer/oauth/authorize\",\n \"tokenUrl\": \"http://yourOAuthServer/oauth/token\",\n \"userInfoUrl\": \"http://yourOAuthServer/userinfo\",\n \"loginUrl\": \"http://yourOAuthServer/login\",\n \"logoutUrl\": \"http://yourOAuthServer/logout?redirectQueryParamName=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\nIf used for BackOffice authentication, the callback url should be `http://otoroshi.oto.tools/backoffice/auth0/callback`.\n\nFor `logoutUrl`, `redirectQueryParamName` is a parameter with a name specific to your OAuth2 provider (for example, in Auth0, this parameter is called `returnTo`, in Kecloak it is called `redirect_uri`).\n\nif you are using a [KeyCloak](https://www.keycloak.org/) server, you can configure it this way, assuming you are using the master realm and you created a new client with a client secret, callback urls set to `http://privateapps.oto.tools/*`.\n\n```json\n{\n \"clientId\": \"clientId\",\n \"clientSecret\": \"clientSecret\",\n \"authorizeUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/auth\",\n \"tokenUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/token\",\n \"userInfoUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/userinfo\",\n \"loginUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/auth\",\n \"logoutUrl\": \"http://keycloakHost/auth/realms/master/protocol/openid-connect/logout?redirect_uri=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\n## Ldap\n\nCreate a new `Ldap auth. provider` config and customize the following informations:\n\n```json\n{\n \"serverUrl\": \"ldap://ldap.forumsys.com:389\",\n \"searchBase\": \"dc=example,dc=com\",\n \"groupFilter\": \"ou=chemists\",\n \"searchFilter\": \"(mail=${username})\",\n \"adminUsername\": \"cn=read-only-admin,dc=example,dc=com\",\n \"adminPassword\": \"password\",\n \"nameField\": \"cn\",\n \"emailField\": \"mail\"\n}\n```\n\n## In Memory\n\nCreate a new `In memory auth. provider` config and then you will be able to create new users. To set the password, just click on the `Set password` button. It will generate a BCrypt hash of the password you typed.\n\n## Auth0\n\nCreate a new OAuth 2 config and add the following informations:\n\n```json\n{\n \"clientId\": \"yourAuth0ClientId\",\n \"clientSecret\": \"yourAuth0ClientSecret\",\n \"authorizeUrl\": \"https://yourAuth0Domain/authorize\",\n \"tokenUrl\": \"https://yourAuth0Domain/oauth/token\",\n \"userInfoUrl\": \"https://yourAuth0Domain/userinfo\",\n \"loginUrl\": \"https://yourAuth0Domain/authorize\",\n \"logoutUrl\": \"https://yourAuth0Domain/v2/logout?returnTo=${redirect}\",\n \"accessTokenField\": \"access_token\",\n \"nameField\": \"name\",\n \"emailField\": \"email\",\n \"otoroshiDataField\": \"app_metadata | otoroshi_data\",\n \"callbackUrl\": \"http://privateapps.oto.tools/privateapps/generic/callback\"\n}\n```\n\nIf you enable Otoroshi exchange protocol, the JWT xill have the following fields (all optional)\n\n* `email`\n* `name`\n* `picture`\n* `user_id`\n* `given_name`\n* `family_name`\n* `gender`\n* `locale`\n* `nickname`\n\nIn Auth0, the metadata is a flat object placed in the `profile / http://yourdomain/app_metadata / otoroshi_data`. You might need to write an Auth0 rule to copy app metadata under `http://yourdomain/app_metadata`, the `http://yourdomain/app_metadata` value is a config property `app.appMeta`. The rule could be something like the following\n\n```js\nfunction (user, context, callback) {\n var namespace = 'http://yourdomain/';\n context.idToken[namespace + 'user_id'] = user.user_id;\n context.idToken[namespace + 'user_metadata'] = user.user_metadata;\n context.idToken[namespace + 'app_metadata'] = user.app_metadata;\n callback(null, user, context);\n}\n```"},{"name":"index.md","id":"/usage/index.md","url":"/usage/index.html","title":"Using Otoroshi","content":"# Using Otoroshi\n\nNow we will see how to use Otoroshi for basic tasks that will be useful for your day to day work with Otoroshi.\n\n@@@ index\n\n* [create group](./1-groups.md)\n* [create service](./2-services.md)\n* [create API Keys](./3-apikeys.md)\n* [monitor service](./4-monitor.md)\n* [sessions management](./5-sessions.md)\n* [Audit trail and alerts](./6-audit.md)\n* [Global metrics](./7-metrics.md)\n* [Exports and imports](./8-importsexports.md)\n* [Authentication](./9-auth.md)\n\n@@@\n"}] \ No newline at end of file diff --git a/docs/manual/css/fonts/icons.eot b/docs/manual/css/fonts/icons.eot new file mode 100644 index 0000000000..a5203e8766 Binary files /dev/null and b/docs/manual/css/fonts/icons.eot differ diff --git a/docs/manual/css/fonts/icons.svg b/docs/manual/css/fonts/icons.svg new file mode 100644 index 0000000000..58c7488236 --- /dev/null +++ b/docs/manual/css/fonts/icons.svg @@ -0,0 +1,12 @@ + + + +Generated by Fontastic.me + + + + + + + + diff --git a/docs/manual/css/fonts/icons.ttf b/docs/manual/css/fonts/icons.ttf new file mode 100644 index 0000000000..6da4b13e05 Binary files /dev/null and b/docs/manual/css/fonts/icons.ttf differ diff --git a/docs/manual/css/fonts/icons.woff b/docs/manual/css/fonts/icons.woff new file mode 100644 index 0000000000..2c7e917bb9 Binary files /dev/null and b/docs/manual/css/fonts/icons.woff differ diff --git a/docs/manual/css/page.css b/docs/manual/css/page.css new file mode 100644 index 0000000000..599d297061 --- /dev/null +++ b/docs/manual/css/page.css @@ -0,0 +1,968 @@ +@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; +} + +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: 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; +} + +.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 > ul > li > ul li a { + font-size: 0.8rem; + padding-left: 2rem; +} + + +/* site navigation */ + +.site-nav { + margin-top: 1rem; + margin-bottom: 1rem; + border: solid 1px #cccccc; +} + +/* 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("../img/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; +} \ No newline at end of file diff --git a/docs/manual/deploy/aws-beanstalk.html b/docs/manual/deploy/aws-beanstalk.html new file mode 100644 index 0000000000..64e757bb6e --- /dev/null +++ b/docs/manual/deploy/aws-beanstalk.html @@ -0,0 +1,615 @@ + + + + +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:8
+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 downstream 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 app.storage=redis, app.redis.host and app.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/clevercloud.html b/docs/manual/deploy/clevercloud.html new file mode 100644 index 0000000000..ac688b8ea9 --- /dev/null +++ b/docs/manual/deploy/clevercloud.html @@ -0,0 +1,495 @@ + + + + +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/index.html b/docs/manual/deploy/index.html new file mode 100644 index 0000000000..4b6c4ee585 --- /dev/null +++ b/docs/manual/deploy/index.html @@ -0,0 +1,429 @@ + + + + +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.

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/deploy/kubernetes.html b/docs/manual/deploy/kubernetes.html new file mode 100644 index 0000000000..f350721a1e --- /dev/null +++ b/docs/manual/deploy/kubernetes.html @@ -0,0 +1,4946 @@ + + + + +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.0-rc.2
+
+

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.0-rc.2-jdk11
+        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
+    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.0-rc.2-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.0-rc.2-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.0-rc.2-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.0-rc.2-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.4.23-dev-jdk11
+        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.0-rc.2-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.4.23-dev-jdk11
+        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.0-rc.2-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.4.23-dev-jdk11
+        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/other.html b/docs/manual/deploy/other.html new file mode 100644 index 0000000000..f9cc6b4fde --- /dev/null +++ b/docs/manual/deploy/other.html @@ -0,0 +1,466 @@ + + + + +Others · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Others

+

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

+

This section is not finished yet. So, as Otoroshi is available as a Docker image that you can run on any Docker compatible cloud, just go ahead and use it on cloud provider until we have more detailed documentation.

+

Running Otoroshi on AWS Elastic Beanstalk

+

See the dedicated page to run Otoroshi on AWS Elastic Beanstalk

+

Running Otoroshi on Amazon Elastic Container Service

+

Deploy the Docker image using Amazon ECS

+

Running Otoroshi on GCE

+

Deploy the Docker image using Google Compute Engine container integration

+

Running Otoroshi on Azure

+

Deploy the Docker image using Azure Container Service

+

Running Otoroshi on Heroku

+

Deploy the Docker image using Docker integration

+

Running Otoroshi on CloudFoundry

+

Deploy the Docker image using Docker integration

+

Running Otoroshi on your own infrastructure

+

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

+

https://www.playframework.com/documentation/2.6.x/ProductionConfiguration

+

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

+ +
+ +
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/deploy/scaling.html b/docs/manual/deploy/scaling.html new file mode 100644 index 0000000000..3402544095 --- /dev/null +++ b/docs/manual/deploy/scaling.html @@ -0,0 +1,691 @@ + + + + +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 new file mode 100644 index 0000000000..7c3c45c75e --- /dev/null +++ b/docs/manual/dev.html @@ -0,0 +1,505 @@ + + + + +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 -Dapp.storage=file -Dapp.liveJs=true -Dhttps.port=9998 -D-Dapp.privateapps.port=9999 -Dapp.adminPassword=password -Dapp.domain=oto.tools -Dplay.server.https.engineProvider=ssl.DynamicSSLEngineProvider -Dapp.events.maxSize=0
+
+

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
+
+

Format the sources

+

from the root of your repository run

+
sh ./scripts/fmt.sh
+
+ +
+ +
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/features.html b/docs/manual/features.html new file mode 100644 index 0000000000..9aedca604b --- /dev/null +++ b/docs/manual/features.html @@ -0,0 +1,542 @@ + + + + +Features · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Features

Warning
+

This section is under construction

+

All the features supported by Otoroshi are listed below

+ + +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/configfile.html b/docs/manual/firstrun/configfile.html new file mode 100644 index 0000000000..c5d4f3933b --- /dev/null +++ b/docs/manual/firstrun/configfile.html @@ -0,0 +1,2285 @@ + + + + +Config. with files · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Config. with files

+

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
+
+

Common configuration

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
app.domain string “oto.tools” the domain on which Otoroshi UI/API is be exposed
app.rootScheme string “http” the scheme on which Otoroshi is exposed, either “http” or “https”
app.snowflake.seed number 0 this number will is used to generate unique ids across the cluster. Each Otorshi instance must have a unique seed.
app.events.maxSize number 1000 max number of analytic and alert events stored locally
app.backoffice.exposed boolean true does the current Otoroshi instance exposed a backoffice ui
app.backoffice.subdomain string “otoroshi” the subdomain on wich Otoroshi backoffice will be served
app.backoffice.session.exp number 86400000 the number of seconds before the Otoroshi backoffice session expires
app.privateapps.subdomain string “privateapps” the subdomain on which private apps UI are served
app.privateapps.session.exp number 86400000 the number of seconds before the private apps session expires
app.claim.sharedKey string “secret” the shared secret used for signing the JWT token passed between Otoroshi and backend services
app.webhooks.size number 100 number of events sent at most when calling one of the analytics webhooks
app.throttlingWindow number 10 time window (in seconds) used to compute throttling quotas for ApiKeys
+

Admin API configuration

+

When Otoroshi starts for the first time, its datastore is empty. As Otoroshi uses Otoroshi to expose its admin REST API, you’ll have to provide the details for the admin API exposition. This part is super important because if you go to production with the default values, your Otoroshi server won’t be secured anymore.

Warning
+

YOU HAVE TO CUSTOMIZE THE FOLLOWING VALUES BEFORE GOING TO PRODUCTION !!

+

Some of the following terms will seem obscure to you, but you will learn their meaning in the following chapters :)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
app.adminapi.exposed boolean true does the current Otoroshi instance expose an admin API
app.adminapi.targetSubdomain string “otoroshi-admin-internal-api” the subdomain on wich admin API call will be redirected from app.adminapi.exposedSubdomain
app.adminapi.exposedSubdomain string “otoroshi-api” the subdomain on wich the Otoroshi admin API will be exposed
app.adminapi.defaultValues.backOfficeGroupId string “admin-api-group” the name of the service groups that will contain the service descriptors for the Otoroshi admin API
app.adminapi.defaultValues.backOfficeApiKeyClientId string “admin-api-apikey-id” the client id of the Otoroshi admin API apikey
app.adminapi.defaultValues.backOfficeApiKeyClientSecret string “admin-api-apikey-secret” the client secret of the Otoroshi admin API apikey
app.adminapi.defaultValues.backOfficeServiceId string “admin-api-service” the id of the service descriptors for the Otoroshi admin API
app.adminapi.proxy.https boolean false whether or not the current Otoroshi instance serves its content over https. This setting is useful for the backoffice UI to access Otoroshi admin API
app.adminapi.proxy.local boolean true whether or not the admin API is accessible through 127.0.0.1. This setting is useful for the backoffice UI to access Otoroshi admin API
+

Secrets config

+

When Otoroshi starts for the first time, its secrets are set by default.

Warning
+

YOU HAVE TO CUSTOMIZE AT LEAST otoroshi.secret BEFORE GOING TO PRODUCTION !!

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
otoroshi.secret string ‘verysecretvaluethatyoumustoverwrite’ default Otoroshi secret. This value is used by default for other secrets
otoroshi.sessions.secret string otoroshi.secret Secret used to cipher session ids
play.http.secret.key string otoroshi.secret the secret used to sign Otoroshi session cookie
+

DB configuration

+

As Otoroshi supports multiple datastores, you’ll have to provide some details about how to connect/configure it.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
app.storage string “inmemory” what kind of storage engine you want to use. Possible values are inmemory, file, redis, cassandra
app.importFrom string  a file path or a URL to an Otoroshi export file. If the datastore is empty on startup, this file will be used to import data to the empty DB
app.importFromHeaders array  [] a list of : separated header to use if the app.importFrom setting is a URL
app.initialData object   object representing Otoroshi internal data as exported from danger zone so you don’t need a config file and a data import file
app.redis.host string “localhost” the host of the redis server
app.redis.port number 6379 the port of the redis server
app.redis.slaves array [] the redis slaves lists
app.filedb.path string “./filefb” the path where filedb files will be written
app.cassandra.hosts string “127.0.0.1” the host of the cassandra server
app.cassandra.host string “127.0.0.1” the list of cassandra hosts
app.cassandra.port number 9042 the port of the cassandra servers
app.pg.uri string the uri of your pg database
app.pg.host string localhost the host of your pg database
app.pg.port number 5432 the port of your pg database
app.pg.database string otoroshi the database name
app.pg.user string otoroshi the username to connect to your pg database
app.pg.password string otoroshi the password to connect to your pg database
+

Headers configuration

+

Otoroshi uses a fair amount of http headers in order to work properly. The name of those headers are customizable to fit your needs.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
otoroshi.headers.trace.label string “Otoroshi-Viz-From-Label” header to pass request tracing informations
otoroshi.headers.trace.from string “Otoroshi-Viz-From” header to pass request tracing informations (ip address)
otoroshi.headers.trace.parent string “Otoroshi-Parent-Request” header to pass request tracing informations (parent request id)
otoroshi.headers.request.adminprofile string “Otoroshi-Admin-Profile” header to pass admin name when the admin API is called from the Otoroshi backoffice
otoroshi.headers.request.clientid string “Otoroshi-Client-Id” header to pass apikey client id
otoroshi.headers.request.clientsecret string “Otoroshi-Client-Secret” header to pass apikey client secret
otoroshi.headers.request.id string “Otoroshi-Request-Id” header containing the id of the current request
otoroshi.headers.response.proxyhost string “Otoroshi-Proxied-Host” header containing the proxied host
otoroshi.headers.response.error string “Otoroshi-Error” header containing whether or not the request generated an error
otoroshi.headers.response.errormsg string “Otoroshi-Error-Msg” header containing error message if some
otoroshi.headers.response.proxylatency string “Otoroshi-Proxy-Latency” header containing the current latency induced by Otoroshi
otoroshi.headers.response.upstreamlatency string “Otoroshi-Upstream-Latency” header containing the current latency from Otoroshi to service backend
otoroshi.headers.response.dailyquota string “Otoroshi-Daily-Calls-Remaining” header containing the number of remaining daily call (apikey)
otoroshi.headers.response.monthlyquota string “Otoroshi-Monthly-Calls-Remaining” header containing the number of remaining monthly call (apikey)
otoroshi.headers.comm.state string “Otoroshi-State” header containing a random value for secured mode
otoroshi.headers.comm.stateresp string “Otoroshi-State-Resp” header containing a random value for secured mode
otoroshi.headers.comm.claim string “Otoroshi-Claim” header containing a JWT token for secured mode
otoroshi.headers.healthcheck.test string “Otoroshi-Health-Check-Logic-Test” header containing a logic test for healthcheck
otoroshi.headers.healthcheck.testresult string “Otoroshi-Health-Check-Logic-Test-Result” header containing the result of a logic test for healthcheck
otoroshi.headers.jwt.issuer string “Otoroshi” the name of the issuer for the JWT token
otoroshi.headers.canary.tracker string “Otoroshi-Canary-Id” header containing the ID of the canary session if enabled
+

Play specific configuration

+

As Otoroshi is a Play app, you should take a look at Play configuration documentation to tune its internal configuration

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
name type default value description
http.port number 8080 the http port used by Otoroshi. You can use ‘disabled’ as value if you don’t want to use http
https.port number disabled the https port used by Otoroshi. You can use ‘disabled’ as value if you don’t want to use https
http2.enabled boolean false whether or not http2 is enabled on the Otoroshi server. You need to configure https (listed bellow) to be able to use it
play.http.secret.key string “secret” the secret used to sign Otoroshi session cookie
play.http.session.secure boolean false whether or not the Otoroshi backoffice session will be served over https only
play.http.session.httpOnly boolean true whether or not the Otoroshi backoffice session will be accessible from Javascript
play.http.session.maxAge number 259200000 the number of seconds before Otoroshi backoffice session expired
play.http.session.domain string “.oto.tools” the domain on which the Otoroshi backoffice session is authorized
play.http.session.cookieName string “otoroshi-session” the name of the Otoroshi backoffice session
play.ws.play.ws.useragent string “Otoroshi” the user agent sent by Otoroshi if not present on the original http request
play.server.https.keyStore.path string the path to the keystore containing the private key and certificate, if not provided generates a keystore for you
play.server.https.keyStore.type string JKS the key store type, defaults to JKS
play.server.https.keyStore.password string ’’ the password, defaults to a blank password
play.server.https.keyStore.algorithm string the key store algorithm, defaults to the platforms default algorithm
+

More config. options

+

See https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/base.conf and https://github.com/MAIF/otoroshi/blob/master/otoroshi/conf/application.conf

+

if you want to configure https on your Otoroshi server, just read PlayFramework documentation about it

+

Example of a custom. configuration file

+
include "application.conf"
+
+http.port = 8080
+
+app {
+  storage = "file"
+  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 + storageRoot = "otoroshi" # the prefix used for storage keys + storageRoot = ${?APP_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 + importFrom = ${?APP_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 + liveJs = false # enabled live JS loading for dev mode + redirectToDev = false #not-used + domain = "oto.tools" # default domain for basic otoroshi services + domain = ${?APP_DOMAIN} # default domain for basic otoroshi services + commitId = "HEAD" + commitId = ${?COMMIT_ID} + rootScheme = "http" # default root scheme when composing urls + rootScheme = ${?APP_ROOT_SCHEME} # default root scheme when composing urls + middleFingers = false #not-used + middleFingers = ${?APP_MIDDLE_FINGERS} #not-used + workers = 30 #not-used + workers = ${?APP_WORKERS} #not-used + throttlingWindow = 10 # the number of second used to compute throttling number + throttlingWindow = ${?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 + overheadThreshold = 500.0 # the value threshold (in milliseconds) used to send HighOverheadAlert + overheadThreshold = ${?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 + } + 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 + } + proxy { #not-used + keepAlive = true #not-used + keepAlive = ${?PROXY_KEEPALIVE} #not-used + compressionEnabled = false #not-used + compressionEnabled = ${?PROXY_COMPRESSION_ENABLED} #not-used + idleTimeout = 3600000 #not-used + idleTimeout = ${?PROXY_IDLE_TIMEOUT} #not-used + connectionTimeout = 120000 #not-used + connectionTimeout = ${?PROXY_CONNECTION_TIMEOUT} #not-used + requestTimeout = 3600000 #not-used + requestTimeout = ${?PROXY_REQUEST_TIMEOUT} #not-used + useAkkaClient = false #not-used + useAkkaClient = ${?PROXY_USE_AKKA_CLIENT} #not-used + } + sidecar { #not-used + serviceId = ${?SIDECAR_SERVICE_ID} #not-used + target = ${?SIDECAR_TARGET} #not-used + from = "127.0.0.1" #not-used + from = ${?SIDECAR_FROM} #not-used + strict = true #not-used + strict = ${?SIDECAR_STRICT} #not-used + apikey { #not-used + clientId = ${?SIDECAR_APIKEY_CLIENT_ID} #not-used + } #not-used + } #not-used + 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 + accessKey = ${?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 = ${?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 + } + 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 + subdomain = "otoroshi" # the backoffice subdomain + subdomain = ${?APP_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 + } + } + privateapps { + subdomain = "privateapps" # privateapps (proxy sso) domain + subdomain = ${?APP_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 + } + } + adminapi { + exposed = true # expose the admin api + exposed = ${?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 + 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 + additionalExposedDomain = ${?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 + backOfficeApiKeyClientId = "admin-api-apikey-id" # default value for admin api apikey id + backOfficeApiKeyClientId = ${?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 = ${?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 + } + proxy { + https = false # backoffice proxy admin api over https + https = ${?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 + } + } + 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 + } + webhooks { + size = 100#not-used + size = ${?WEBHOOK_SIZE}#not-used + } + redis { # configuration to fetch/store otoroshi state from a redis datastore using rediscala + host = "localhost" + host = ${?REDIS_HOST} + port = 6379 + port = ${?REDIS_PORT} + password = ${?REDIS_PASSWORD} + windowSize = 99 + windowSize = ${?REDIS_WINDOW_SIZE} + slaves = [] + slavesStr = ${?REDIS_SLAVES} + slavesStr = ${?REDIS_MEMBERS} + useScan = false + useScan = ${?REDIS_USE_SCAN} + + pool { + members = [] + members = ${?REDIS_POOL_MEMBERS} + } + + mpool { + members = [] + membersStr = ${?REDIS_MPOOL_MEMBERS} + } + + lf { + master { + host = ${?REDIS_LF_HOST} + port = ${?REDIS_LF_PORT} + password = ${?REDIS_LF_PASSWORD} + } + slaves = [] + slavesStr = ${?REDIS_LF_SLAVES} + slavesStr = ${?REDIS_LF_MEMBERS} + } + + sentinels { + master = ${?REDIS_SENTINELS_MASTER} + password = ${?REDIS_SENTINELS_PASSWORD} + db = ${?REDIS_SENTINELS_DB} + name = ${?REDIS_SENTINELS_NAME} + members = [] + membersStr = ${?REDIS_SENTINELS_MEMBERS} + + lf { + master = ${?REDIS_SENTINELS_LF_MASTER} + members = [] + membersStr = ${?REDIS_SENTINELS_LF_MEMBERS} + } + } + + cluster { + members = [] + membersStr = ${?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} + uri = ${?REDIS_LETTUCE_URI} + uri = ${?REDIS_URL} + uris = [] + urisStr = ${?REDIS_LETTUCE_URIS} + readFrom = "MASTER_PREFERRED" + readFrom = ${?REDIS_LETTUCE_READ_FROM} + startTLS = false + startTLS = ${?REDIS_LETTUCE_START_TLS} + verifyPeers = true + verifyPeers = ${?REDIS_LETTUCE_VERIFY_PEERS} + } + } + inmemory { # configuration to fetch/store otoroshi state in memory + windowSize = 99 + windowSize = ${?INMEMORY_WINDOW_SIZE} + experimental = false + experimental = ${?INMEMORY_EXPERIMENTAL_STORE} + optimized = false + optimized = ${?INMEMORY_OPTIMIZED} + } + leveldb { #not-used + windowSize = 99 #not-used + windowSize = ${?LEVELDB_WINDOW_SIZE} #not-used + path = "./leveldb" #not-used + path = ${?LEVELDB_PATH} #not-used + } #not-used + filedb { # configuration to fetch/store otoroshi state from a file + windowSize = 99 + windowSize = ${?FILEDB_WINDOW_SIZE} + path = "./filedb/state.ndjson" + path = ${?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 = ${?POSTGRESQL_ADDON_URI} + poolSize = 20 + poolSize = ${?PG_POOL_SIZE} + port = 5432 + port = ${?PG_PORT} + host = "localhost" + host = ${?PG_HOST} + database = "otoroshi" + database = ${?PG_DATABASE} + user = "otoroshi" + user = ${?PG_USER} + password = "otoroshi" + password = ${?PG_PASSWORD} + logQueries = ${?PG_DEBUG_QUERIES} + avoidJsonPath = false + avoidJsonPath = ${?PG_AVOID_JSON_PATH} + optimized = true + optimized = ${?PG_OPTIMIZED} + connect-timeout = ${?PG_CONNECT_TIMEOUT} + idle-timeout = ${?PG_IDLE_TIMEOUT} + log-activity = ${?PG_LOG_ACTIVITY} + pipelining-limit = ${?PG_PIPELINING_LIMIT} + ssl { + enabled = false + enabled = ${?PG_SSL_ENABLED} + mode = "verify_ca" + mode = ${?PG_SSL_MODE} + trusted-certs-path = [] + trusted-certs = [] + trusted-cert-path = ${?PG_SSL_TRUSTED_CERT_PATH} + trusted-cert = ${?PG_SSL_TRUSTED_CERT} + client-certs-path = [] + client-certs = [] + client-cert-path = ${?PG_SSL_CLIENT_CERT_PATH} + client-cert = ${?PG_SSL_CLIENT_CERT} + trust-all = ${?PG_SSL_TRUST_ALL} + } + } + cassandra { # cassandra settings. everything possible with the client + windowSize = 99 + windowSize = ${?CASSANDRA_WINDOW_SIZE} + host = "127.0.0.1" + host = ${?CASSANDRA_HOST} + port = 9042 + port = ${?CASSANDRA_PORT} + replicationFactor = 1 + replicationFactor = ${?CASSANDRA_REPLICATION_FACTOR} + replicationOptions = ${?CASSANDRA_REPLICATION_OPTIONS} + durableWrites = true + durableWrites = ${?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 + } + } + mongo { #not-used + uri = "mongodb://localhost:27017/default" #not-used + uri = ${?MONGO_URI} #not-used + windowSize = 99 #not-used + windowSize = ${?CASSANDRA_WINDOW_SIZE} #not-used + } #not-used + kafka { #not-used + host = "127.0.0.1" #not-used + host = ${?KAFKA_HOST} #not-used + port = "9092" #not-used + port = ${?KAFKA_PORT} #not-used + servers = ${app.kafka.host}":"${app.kafka.port} #not-used + servers = ${?KAFKA_HOSTS_AND_PORTS} #not-used + groupId = "otoroshi" #not-used + nbPartitions = 3 #not-used + nbPartitions = ${?KAFKA_NB_PARTITIONS} #not-used + keyPass = ${?KAFKA_PASSWORD} #not-used + keystore { #not-used + location = ${?KAFKA_KEYSTORE_LOCATION} #not-used + } #not-used + truststore { #not-used + location = ${?KAFKA_TRUSTORE_LOCATION} #not-used + } #not-used + } #not-used + actorsystems { + otoroshi { + akka { # otoroshi actorsystem configuration + 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_MAX_CHUNK_SIZE} + max-content-length = infinite + max-content-length = ${?AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT} + max-to-strict-bytes = infinite + max-to-strict-bytes = ${?AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES} + } + } + } + } + datastore { + akka { + 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 { + instance = ${app.instance} # instance name + 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 + 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_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_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} + } + # 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 = ${?INITIAL_CACERT} + initialCert = ${?CLUSTER_WORKER_INITIAL_CERT} + initialCert = ${?INITIAL_CERT} + initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY} + initialCertKey = ${?INITIAL_CERT_KEY} + # initialCerts = [] + genWildcardCert = true #not-used + genWildcardCert = ${?OTOROSHI_SSL_GEN_WILDCARD_CERT} #not-used + } + cluster { + mode = "off" # can be "off", "leader", "worker" + mode = ${?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 + retryDelay = 300 # the delay before retrying a request to leader + retryDelay = ${?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 + selfAddress = ${?CLUSTER_SELF_ADDRESS} # the cluster slefAddress + autoUpdateState = true # auto update cluster state with a job (mor efficient) + autoUpdateState = ${?CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (mor efficient + mtls { + # certs = [] + # trustedCerts = [] + enabled = false # enable mtls + enabled = ${?CLUSTER_MTLS_ENABLED} # enable mtls + loose = false # loose verification + loose = ${?CLUSTER_MTLS_LOOSE} # loose verification + trustAll = false # trust any CA + trustAll = ${?CLUSTER_MTLS_TRUST_ALL} # trust any CA + } + leader { + name = ${?CLUSTER_LEADER_NAME} # the leader name + urls = ["http://127.0.0.1:8080"] # the leader urls + url = ${?CLUSTER_LEADER_URL} # the leader url + host = "otoroshi-api.oto.tools" # the leaders api hostname + host = ${?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 + 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 + groupingBy = 50 # items grouping when streaming state + groupingBy = ${?CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state + cacheStateFor = 4000 # the ttl for local state cache + cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache + stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose + } + worker { + name = ${?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 + timeout = 2000 # the workers timeout when interacting with leaders + timeout = ${?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 + dbpath = ${?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 + 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 + 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 + pollEvery = 10000 # polling interval + pollEvery = ${?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 + } + 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 + pushEvery = 2000 # pushing interval + pushEvery = ${?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 + } + } + 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 { + 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-content-length = infinite + max-content-length = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT} + max-to-strict-bytes = infinite + max-to-strict-bytes = ${?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} + } +} + + +http.port = 8080 # the main http port for the otoroshi server +http.port = ${?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 +https.port = 8443 # the main https port for the otoroshi server +https.port = ${?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.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.server.http.idleTimeout = 3600s # the default server idle timeout +play.server.http.idleTimeout = ${?PLAY_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) + +http2.enabled = true # enable HTTP2 support +http2.enabled = ${?HTTP2_ENABLED} # enable HTTP2 support + +play.server.https.keyStore.path=${?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.password=${?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.wantClientAuth = false # mTLS Want client auth settings (client cert COULD be provided) #not-used +play.server.https.wantClientAuth = ${?HTTPS_WANT_CLIENT_AUTH} # mTLS Want client auth settings (client cert COULD be provided) #not-used +play.server.https.needClientAuth = false # mTLS Need client auth settings (client cert MUST be provided) #not-used +play.server.https.needClientAuth = ${?HTTPS_NEED_CLIENT_AUTH} # mTLS Need client auth settings (client cert MUST be provided) #not-used + +play.server.pidfile.path = "/dev/null" # pid file path #not-used + +play.modules { #not-used +} #not-used + +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 + 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 + domain = "."${app.domain} # the cookie for otoroshi backoffice domain + domain = ${?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 + } +} + +play.http.filters = play.api.http.NoHttpFilters #not-used +play.filters.enabled = [] #not-used + +play.ws { #not-used + useragent="Otoroshi-ahc" #not-used + useragent=${?USER_AGENT} #not-used + ssl { #not-used + } #not-used +} #not-used + +play.cache { #not-used +} #not-used + +akka { #not-used + jvm-exit-on-fatal-error = off #not-used +} #not-used + +play.akka { #not-used + jvm-exit-on-fatal-error = off #not-used +} #not-used + + +akka { # akka specific configuration + 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-min = 4 + parallelism-max = 64 + task-peeking-mode = "FIFO" + } + throughput = 1 + } + } + 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 = 1024 + 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-content-length = infinite + max-content-length = ${?AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT} + } + } +}
+ +
+ +
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/datastore.html b/docs/manual/firstrun/datastore.html new file mode 100644 index 0000000000..23dd3341bb --- /dev/null +++ b/docs/manual/firstrun/datastore.html @@ -0,0 +1,444 @@ + + + + +Choose your datastore · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Choose your datastore

+

Right now, Otoroshi supports multiple datastore.

+

You can choose one datastore over another depending on your use case.

+

Available datastores are the following :

+
    +
  • in memory
  • +
  • redis
  • +
  • cassandra (experimental support, should be used in cluster mode for leaders)
  • +
  • postgresql or any postgresql compatible databse like cockroachdb for instance (experimental support, should be used in cluster mode for leaders)
  • +
  • filedb (not suitable for production usage)
  • +
+

The filedb datastore is pretty handy for testing purposes, but is not supposed to be used in production mode.

+

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. You can check the clustering documentation to find more about it.

+

The redis datastore is quite nice when you want to easily deploy several Otoroshi instances.

+

If you need a datastore more scalable than redis, then you can use the postgresql or cassandra datastore.

+
+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/env.html b/docs/manual/firstrun/env.html new file mode 100644 index 0000000000..bcf940415c --- /dev/null +++ b/docs/manual/firstrun/env.html @@ -0,0 +1,1100 @@ + + + + +Config. with ENVs · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Config. with ENVs

+

Now that you know how to configure Otoroshi with the config. file every property in the following block can be overriden by an environment variable (an env. variable is 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  
+  storageRoot = ${?APP_STORAGE_ROOT} # the prefix used for storage keys
+  eventsName = ${?APP_EVENTS_NAME} # the name of the event producer
+  importFrom = ${?APP_IMPORT_FROM} # file path to import otoroshi initial configuration
+  env = ${?APP_ENV} # env name, should always be prod except in dev mode
+  domain = ${?APP_DOMAIN} # default domain for basic otoroshi services
+  commitId = ${?COMMIT_ID}
+  rootScheme = ${?APP_ROOT_SCHEME} # default root scheme when composing urls
+  middleFingers = ${?APP_MIDDLE_FINGERS} #not-used
+  workers = ${?APP_WORKERS} #not-used
+  throttlingWindow = ${?THROTTLING_WINDOW} # the number of second used to compute throttling number
+  checkForUpdates = ${?CHECK_FOR_UPDATES} # enable automatic version update checks
+  overheadThreshold = ${?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
+  }
+  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
+  }
+  proxy { #not-used
+    keepAlive = ${?PROXY_KEEPALIVE} #not-used
+    compressionEnabled = ${?PROXY_COMPRESSION_ENABLED} #not-used
+    idleTimeout = ${?PROXY_IDLE_TIMEOUT} #not-used
+    connectionTimeout = ${?PROXY_CONNECTION_TIMEOUT} #not-used
+    requestTimeout = ${?PROXY_REQUEST_TIMEOUT} #not-used
+    useAkkaClient = ${?PROXY_USE_AKKA_CLIENT} #not-used
+  }
+  sidecar { #not-used
+    serviceId = ${?SIDECAR_SERVICE_ID} #not-used
+    target = ${?SIDECAR_TARGET} #not-used
+    from = ${?SIDECAR_FROM} #not-used
+    strict = ${?SIDECAR_STRICT} #not-used
+    apikey { #not-used
+      clientId = ${?SIDECAR_APIKEY_CLIENT_ID} #not-used
+    } #not-used
+  } #not-used
+  health {
+    limit = ${?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
+  }
+  snowflake {
+    seed = ${?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
+  }
+  events {
+    maxSize = ${?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
+    subdomain = ${?APP_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
+    }
+  }
+  privateapps {
+    subdomain = ${?APP_PRIVATEAPPS_SUBDOMAIN} # privateapps (proxy sso) domain
+    domainsStr = ${?APP_PRIVATEAPPS_DOMAINS}
+    domainsStr = ${?OTOROSHI_PRIVATEAPPS_DOMAINS}
+    session {
+      exp = ${?APP_PRIVATEAPPS_SESSION_EXP} # the privateapps cookie expiration
+    }
+  }
+  adminapi {
+    exposed = ${?ADMIN_API_EXPOSED} # expose the admin api
+    targetSubdomain = ${?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
+    additionalExposedDomain = ${?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
+      backOfficeApiKeyClientId = ${?ADMIN_API_CLIENT_ID}  # default value for admin api apikey id
+      backOfficeApiKeyClientSecret = ${?otoroshi.admin-api-secret} # default value for admin api apikey secret
+      backOfficeApiKeyClientSecret = ${?ADMIN_API_CLIENT_SECRET} # default value for admin api apikey secret
+      backOfficeServiceId = ${?ADMIN_API_SERVICE_ID} # default value for admin api service id
+    }
+    proxy {
+      https = ${?ADMIN_API_HTTPS} # backoffice proxy admin api over https
+      local = ${?ADMIN_API_LOCAL} # backoffice proxy admin api on localhost
+    }
+  }
+  claim {
+    sharedKey = ${?CLAIM_SHAREDKEY} # the default secret used to sign otoroshi exchange protocol tokens
+  }
+  webhooks {
+    size = ${?WEBHOOK_SIZE}#not-used
+  }
+  redis { # configuration to fetch/store otoroshi state from a redis datastore using rediscala
+    host = ${?REDIS_HOST}
+    port = ${?REDIS_PORT}
+    password = ${?REDIS_PASSWORD}
+    windowSize = ${?REDIS_WINDOW_SIZE}
+    slavesStr = ${?REDIS_SLAVES}
+    slavesStr = ${?REDIS_MEMBERS}
+    useScan =  ${?REDIS_USE_SCAN}
+    pool {
+      members = ${?REDIS_POOL_MEMBERS}
+    }
+    mpool {
+      membersStr = ${?REDIS_MPOOL_MEMBERS}
+    }
+    lf {
+      master {
+        host = ${?REDIS_LF_HOST}
+        port = ${?REDIS_LF_PORT}
+        password = ${?REDIS_LF_PASSWORD}
+      }
+      slavesStr = ${?REDIS_LF_SLAVES}
+      slavesStr = ${?REDIS_LF_MEMBERS}
+    }
+    sentinels {
+      master = ${?REDIS_SENTINELS_MASTER}
+      password = ${?REDIS_SENTINELS_PASSWORD}
+      db = ${?REDIS_SENTINELS_DB}
+      name = ${?REDIS_SENTINELS_NAME}
+      membersStr = ${?REDIS_SENTINELS_MEMBERS}
+      lf {
+        master = ${?REDIS_SENTINELS_LF_MASTER}
+        membersStr = ${?REDIS_SENTINELS_LF_MEMBERS}
+      }
+    }
+    cluster {
+      membersStr = ${?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}
+      uri =  ${?REDIS_LETTUCE_URI}
+      uri =  ${?REDIS_URL}
+      urisStr = ${?REDIS_LETTUCE_URIS}
+      readFrom = ${?REDIS_LETTUCE_READ_FROM}
+      startTLS = ${?REDIS_LETTUCE_START_TLS}
+      verifyPeers = ${?REDIS_LETTUCE_VERIFY_PEERS}
+    }
+  }
+  inmemory { # configuration to fetch/store otoroshi state in memory
+    windowSize = ${?INMEMORY_WINDOW_SIZE}
+    experimental = ${?INMEMORY_EXPERIMENTAL_STORE}
+    optimized = ${?INMEMORY_OPTIMIZED}
+  }
+  leveldb { #not-used
+    windowSize = ${?LEVELDB_WINDOW_SIZE} #not-used
+    path = ${?LEVELDB_PATH} #not-used
+  } #not-used
+  filedb { # configuration to fetch/store otoroshi state from a file
+    windowSize = ${?FILEDB_WINDOW_SIZE}
+    path = ${?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 = ${?POSTGRESQL_ADDON_URI}
+    poolSize = ${?PG_POOL_SIZE}
+    port = ${?PG_PORT}
+    host = ${?PG_HOST}
+    database = ${?PG_DATABASE}
+    user = ${?PG_USER}
+    password = ${?PG_PASSWORD}
+    logQueries = ${?PG_DEBUG_QUERIES}
+    avoidJsonPath = ${?PG_AVOID_JSON_PATH}
+    optimized = ${?PG_OPTIMIZED}
+    connect-timeout = ${?PG_CONNECT_TIMEOUT}
+    idle-timeout = ${?PG_IDLE_TIMEOUT}
+    log-activity = ${?PG_LOG_ACTIVITY}
+    pipelining-limit = ${?PG_PIPELINING_LIMIT}
+    ssl {
+      enabled = ${?PG_SSL_ENABLED}
+      mode = ${?PG_SSL_MODE}
+      trusted-cert-path = ${?PG_SSL_TRUSTED_CERT_PATH}
+      trusted-cert = ${?PG_SSL_TRUSTED_CERT}
+      client-cert-path = ${?PG_SSL_CLIENT_CERT_PATH}
+      client-cert = ${?PG_SSL_CLIENT_CERT}
+      trust-all = ${?PG_SSL_TRUST_ALL}
+    }
+  }
+  cassandra { # cassandra settings. everything possible with the client
+    windowSize = ${?CASSANDRA_WINDOW_SIZE}
+    host = ${?CASSANDRA_HOST}
+    port = ${?CASSANDRA_PORT}
+    replicationFactor = ${?CASSANDRA_REPLICATION_FACTOR}
+    replicationOptions = ${?CASSANDRA_REPLICATION_OPTIONS}
+    durableWrites = ${?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 {
+    }
+  }
+  mongo { #not-used
+    uri = ${?MONGO_URI} #not-used
+    windowSize = ${?CASSANDRA_WINDOW_SIZE} #not-used
+  } #not-used
+  kafka { #not-used
+    host = ${?KAFKA_HOST} #not-used
+    port = ${?KAFKA_PORT} #not-used
+    servers = ${app.kafka.host}":"${app.kafka.port} #not-used
+    servers = ${?KAFKA_HOSTS_AND_PORTS} #not-used
+    nbPartitions = ${?KAFKA_NB_PARTITIONS} #not-used
+    keyPass = ${?KAFKA_PASSWORD} #not-used
+    keystore { #not-used
+      location = ${?KAFKA_KEYSTORE_LOCATION} #not-used
+    } #not-used
+    truststore { #not-used
+      location = ${?KAFKA_TRUSTORE_LOCATION} #not-used
+    } #not-used
+  } #not-used
+  actorsystems {
+    otoroshi {
+      akka { # otoroshi actorsystem configuration
+        default-dispatcher {
+          fork-join-executor {
+          }
+        }
+        http {
+          parsing {
+            max-chunk-size             = ${?AKKA_HTTP_CLIENT_MAX_CHUNK_SIZE}
+            max-content-length         = ${?AKKA_HTTP_CLIENT_MAX_CONTENT_LENGHT}
+            max-to-strict-bytes        = ${?AKKA_HTTP_CLIENT_MAX_TO_STRICT_BYTES}
+          }
+        }
+      }
+    }
+    datastore {
+      akka {
+        default-dispatcher {
+          fork-join-executor {
+          }
+        }
+      }
+    }
+  }
+}
+otoroshi {
+  instance = ${app.instance} # instance name
+  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
+  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_ENTITIES_CACHE_ENABLED}
+    ttl = ${?OTOROSHI_ENTITIES_CACHE_TTL}
+  }
+  metrics {
+    enabled = ${?OTOROSHI_METRICS_ENABLED}
+    every = ${?OTOROSHI_METRICS_EVERY}
+    accessKey = ${?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}
+    }
+    trust {
+      all = ${?OTOROSHI_SSL_TRUST_ALL}
+    }
+    initialCacert = ${?CLUSTER_WORKER_INITIAL_CACERT}
+    initialCacert = ${?INITIAL_CACERT}
+    initialCert = ${?CLUSTER_WORKER_INITIAL_CERT}
+    initialCert = ${?INITIAL_CERT}
+    initialCertKey = ${?CLUSTER_WORKER_INITIAL_CERT_KEY}
+    initialCertKey = ${?INITIAL_CERT_KEY}
+    genWildcardCert = ${?OTOROSHI_SSL_GEN_WILDCARD_CERT} #not-used
+  }
+  cluster {
+    mode = ${?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
+    retryDelay = ${?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
+    selfAddress = ${?CLUSTER_SELF_ADDRESS} # the cluster slefAddress
+    autoUpdateState = ${?CLUSTER_AUTO_UPDATE_STATE} # auto update cluster state with a job (mor efficient
+    mtls {
+      enabled = ${?CLUSTER_MTLS_ENABLED}  # enable mtls
+      loose = ${?CLUSTER_MTLS_LOOSE}  # loose verification
+      trustAll = ${?CLUSTER_MTLS_TRUST_ALL} # trust any CA
+    }
+    leader {
+      name = ${?CLUSTER_LEADER_NAME} # the leader name
+      url = ${?CLUSTER_LEADER_URL} # the leader url
+      host = ${?CLUSTER_LEADER_HOST} # the leaders api hostname
+      clientId = ${?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
+      groupingBy = ${?CLUSTER_LEADER_GROUP_BY} # items grouping when streaming state
+      cacheStateFor = ${?CLUSTER_LEADER_CACHE_STATE_FOR} # the ttl for local state cache
+      stateDumpPath = ${?CLUSTER_LEADER_DUMP_PATH} # eventually a dump state path for debugging purpose
+    }
+    worker {
+      name = ${?CLUSTER_WORKER_NAME} # the workers name
+      retries = ${?CLUSTER_WORKER_RETRIES} # the number of retries when pushing quotas/pulling state
+      timeout = ${?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
+      dbpath = ${?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
+      swapStrategy = ${?CLUSTER_WORKER_SWAP_STRATEGY} # the internal memory store strategy, can be Replace or Merge
+      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
+        pollEvery = ${?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
+      }
+      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
+        pushEvery = ${?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
+      }
+    }
+    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 {
+          default-dispatcher {
+            fork-join-executor {
+            }
+          }
+          http {
+            parsing {
+              max-chunk-size             = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CHUNK_SIZE}
+              max-content-length         = ${?AKKA_HTTP_CLIENT_ANALYTICS_MAX_CONTENT_LENGHT}
+              max-to-strict-bytes        = ${?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}
+  }
+}
+http.port = ${?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
+https.port = ${?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.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.server.http.idleTimeout = ${?PLAY_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)
+http2.enabled = ${?HTTP2_ENABLED}  # enable HTTP2 support
+play.server.https.keyStore.path=${?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.password=${?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.wantClientAuth = ${?HTTPS_WANT_CLIENT_AUTH}   # mTLS Want client auth settings (client cert COULD be provided) #not-used
+play.server.https.needClientAuth = ${?HTTPS_NEED_CLIENT_AUTH}   # mTLS Need client auth settings (client cert MUST be provided)  #not-used
+play.modules { #not-used
+} #not-used
+play.http {
+  session {
+    secure = ${?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
+    domain = "."${app.domain}         # the cookie for otoroshi backoffice domain
+    domain = ${?SESSION_DOMAIN}       # the cookie for otoroshi backoffice domain
+    cookieName = ${?SESSION_NAME}     # the cookie for otoroshi backoffice name
+  }
+}
+play.ws { #not-used
+  useragent=${?USER_AGENT} #not-used
+  ssl { #not-used
+  } #not-used
+} #not-used
+play.cache { #not-used
+} #not-used
+akka { #not-used
+} #not-used
+play.akka { #not-used
+} #not-used
+akka { # akka specific configuration
+  actor {
+    default-dispatcher {
+      fork-join-executor {     
+      }
+    }
+  }
+  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-content-length         = ${?AKKA_HTTP_SERVER_MAX_CONTENT_LENGHT}
+    }
+  }
+}
+ +
+
+ +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/host.html b/docs/manual/firstrun/host.html new file mode 100644 index 0000000000..8168980fcb --- /dev/null +++ b/docs/manual/firstrun/host.html @@ -0,0 +1,441 @@ + + + + +Setup your hosts · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Setup your hosts

+

By default, Otoroshi starts with domain oto.tools that targets 127.0.0.1. Of course you can change the domain, you have to add the values in your /etc/hosts file according to the setting you put in Otoroshi configuration

+
    +
  • app.domain => oto.tools
  • +
  • app.backoffice.subdomain => otoroshi
  • +
  • app.privateapps.subdomain => privateapps
  • +
  • app.adminapi.exposedSubdomain => otoroshi-api
  • +
  • app.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 -Dapp.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 app.domain and the settings listed on this page and in the * Config. with files page that serve Otoroshi API and UI on http://otoroshi-api.${app.domain} and http://otoroshi.${app.domain}. Once the descriptor is saved in database, if you want to change app.domain, you’ll have to edit the descriptor in the database or restart Otoroshi with an empty database.

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/index.html b/docs/manual/firstrun/index.html new file mode 100644 index 0000000000..8784739ef6 --- /dev/null +++ b/docs/manual/firstrun/index.html @@ -0,0 +1,431 @@ + + + + +First run · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

First run

+

Now that you have your own distro of Otoroshi, it’s time to run it.

+

But before doing so, you’ll have to make some choices about some essential stuff in order to have your own customized version of Otoroshi.

+

Let’s start with the datastore

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/initialstate.html b/docs/manual/firstrun/initialstate.html new file mode 100644 index 0000000000..f72029aa33 --- /dev/null +++ b/docs/manual/firstrun/initialstate.html @@ -0,0 +1,545 @@ + + + + +Import initial state · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Import initial state

+

Now you are almost ready to run Otoroshi for the first time, but maybe you want to import data from previous Otoroshi installation in your current datastore.

+

To do that, you need to add the app.importFrom setting to the Otoroshi configuration (of $APP_IMPORT_FROM env).

+

It can be a file path or a URL

+

Example of export

+
{
+  "config": {
+    "lines": ["prod"],    
+    "limitConcurrentRequests": true,
+    "maxConcurrentRequests": 500,
+    "useCircuitBreakers": true,
+    "apiReadOnly": false,
+    "registerFromCleverHook": false,
+    "u2fLoginOnly": true,
+    "ipFiltering": {
+      "whitelist": [],
+      "blacklist": []
+    },
+    "throttlingQuota": 100000,
+    "perIpThrottlingQuota": 500,
+    "analyticsEventsUrl": null,
+    "analyticsWebhooks": [],
+    "alertsWebhooks": [],
+    "alertsEmails": [],
+    "endlessIpAddresses": []
+  },
+  "admins": [],
+  "simpleAdmins": [
+    {
+      "username": "admin@otoroshi.io",
+      "password": "xxxxxxxxxxxxxxxxx",
+      "label": "Otoroshi Admin",
+      "createdAt": 1493971715708
+    }
+  ],
+  "serviceGroups": [
+    {
+      "id": "default",
+      "name": "default-group",
+      "description": "The default group"
+    },
+    {
+      "id": "admin-api-group",
+      "name": "Otoroshi Admin Api group",
+      "description": "No description"
+    }
+  ],
+  "apiKeys": [
+    {
+      "clientId": "admin-api-apikey-id",
+      "clientSecret": "admin-api-apikey-secret",
+      "clientName": "Otoroshi Backoffice ApiKey",
+      "authorizedEntities": ["group_admin-api-group"],
+      "enabled": true,
+      "throttlingQuota": 10000000,
+      "dailyQuota": 10000000,
+      "monthlyQuota": 10000000,
+      "metadata": {}
+    }
+  ],
+  "serviceDescriptors": [
+    {
+      "id": "admin-api-service",
+      "groupId": "admin-api-group",
+      "name": "otoroshi-admin-api",
+      "env": "prod",
+      "domain": "oto.tools",
+      "subdomain": "otoroshi-api",
+      "targets": [
+        {
+          "host": "localhost:8080",
+          "scheme": "http"
+        }
+      ],
+      "root": "/",
+      "enabled": true,
+      "privateApp": false,
+      "forceHttps": false,
+      "maintenanceMode": false,
+      "buildMode": false,
+      "enforceSecureCommunication": true,
+      "publicPatterns": [],
+      "privatePatterns": [],
+      "additionalHeaders": {
+        "Host": "otoroshi-admin-internal-api.oto.tools"
+      },
+      "matchingHeaders": {},
+      "ipFiltering": {
+        "whitelist": [],
+        "blacklist": []
+      },
+      "api": {
+        "exposeApi": false
+      },
+      "healthCheck": {
+        "enabled": false,
+        "url": "/"
+      },
+      "metadata": {}
+    }
+  ],
+  "errorTemplates": []
+}
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/firstrun/run.html b/docs/manual/firstrun/run.html new file mode 100644 index 0000000000..bd8802ffc6 --- /dev/null +++ b/docs/manual/firstrun/run.html @@ -0,0 +1,501 @@ + + + + +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

+
unzip otoroshi-dist.zip
+cd otoroshi-vx.x.x
+./bin/otoroshi
+
+

From .jar file

+

For Java 8 & Java 11

+
java -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 -Dapp.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 -Dapp.importFrom=/usr/app/otoroshi/imports/export.json
+
+

Run examples

+
$ java \
+  -Xms2G \
+  -Xmx8G \
+  -Dhttp.port=8080 \
+  -Dapp.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/getotoroshi/frombinaries.html b/docs/manual/getotoroshi/frombinaries.html new file mode 100644 index 0000000000..6c7cd6ac53 --- /dev/null +++ b/docs/manual/getotoroshi/frombinaries.html @@ -0,0 +1,431 @@ + + + + +From binaries · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

From binaries

+

If you want to download the last version of Otoroshi and its CLI, you can grab them from the release page of the Otoroshi github page :

+

Go to https://github.com/MAIF/otoroshi/releases and get the last version of the otoroshi-dist.zip file or otoroshi.jar file

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/getotoroshi/fromdocker.html b/docs/manual/getotoroshi/fromdocker.html new file mode 100644 index 0000000000..3e64bc09c9 --- /dev/null +++ b/docs/manual/getotoroshi/fromdocker.html @@ -0,0 +1,445 @@ + + + + +From docker · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

From docker

+

If you’re a Docker aficionado, Otoroshi is provided as a Docker image that your can pull directly from Official repos.

+

first, fetch the last Docker image of Otoroshi :

+
docker pull maif/otoroshi:1.5.0-rc.2
+# or 
+docker pull maif/otoroshi:latest
+# or 
+docker pull maif/otoroshi:jdk8-1.5.0-rc.2
+# or 
+docker pull maif/otoroshi:jdk11-1.5.0-rc.2
+# or 
+docker pull maif/otoroshi:jdk12-1.5.0-rc.2
+# or 
+docker pull maif/otoroshi:jdk13-1.5.0-rc.2
+# or 
+docker pull maif/otoroshi:jdk14-1.5.0-rc.2
+
+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/getotoroshi/fromsources.html b/docs/manual/getotoroshi/fromsources.html new file mode 100644 index 0000000000..372812c5a3 --- /dev/null +++ b/docs/manual/getotoroshi/fromsources.html @@ -0,0 +1,477 @@ + + + + +From sources · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

From sources

+

to build Otoroshi from sources, you need the following tools :

+
    +
  • git
  • +
  • JDK 8
  • +
  • SBT
  • +
  • node
  • +
  • yarn
  • +
+

Once you’ve installed all those tools, go to the Otoroshi github page and clone the sources :

+
git clone https://github.com/MAIF/otoroshi.git --depth=1
+
+

then you need to run the build.sh script to build the documentation, the React UI and the server :

+
sh ./scripts/build.sh
+
+

and that’s all, you can grab your Otoroshi package at otoroshi/target/scala-2.12/otoroshi or otoroshi/target/universal/.

+

For those who want to build only parts of Otoroshi, read the following.

+

Build the documentation only

+

Go to the documentation folder and run :

+
sbt ';clean;paradox'
+
+

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

+

Build the React UI

+

Go to the otoroshi/javascript folder and run :

+
yarn install
+yarn build
+
+

You will find the JS bundle at otoroshi/public/javascripts/bundle/bundle.js.

+

Build the Otoroshi server

+

Go to the otoroshi folder and run :

+
export SBT_OPTS="-Xmx2G -Xss6M"
+sbt ';clean;compile;dist;assembly'
+
+

You will find your Otoroshi package at otoroshi/target/scala-2.12/otoroshi or otoroshi/target/universal/.

+ +
+ +
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/getotoroshi/index.html b/docs/manual/getotoroshi/index.html new file mode 100644 index 0000000000..ebb68eb762 --- /dev/null +++ b/docs/manual/getotoroshi/index.html @@ -0,0 +1,430 @@ + + + + +Get Otoroshi · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Get Otoroshi

+

There are several ways to get Otoroshi to run it on your system.

+

Let’s start with a good old build from sources :)

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/img/add-apikey.png b/docs/manual/img/add-apikey.png new file mode 100644 index 0000000000..657427c4db Binary files /dev/null and b/docs/manual/img/add-apikey.png differ diff --git a/docs/manual/img/admin-created-admin.png b/docs/manual/img/admin-created-admin.png new file mode 100644 index 0000000000..9466cea945 Binary files /dev/null and b/docs/manual/img/admin-created-admin.png differ diff --git a/docs/manual/img/admin-sessions.png b/docs/manual/img/admin-sessions.png new file mode 100644 index 0000000000..d6cf37bd3f Binary files /dev/null and b/docs/manual/img/admin-sessions.png differ diff --git a/docs/manual/img/admin-users-sessions.png b/docs/manual/img/admin-users-sessions.png new file mode 100644 index 0000000000..0dedb72b5c Binary files /dev/null and b/docs/manual/img/admin-users-sessions.png differ diff --git a/docs/manual/img/alerts-log-content.png b/docs/manual/img/alerts-log-content.png new file mode 100644 index 0000000000..f55b38ca3d Binary files /dev/null and b/docs/manual/img/alerts-log-content.png differ diff --git a/docs/manual/img/alerts-log.png b/docs/manual/img/alerts-log.png new file mode 100644 index 0000000000..553e27bdab Binary files /dev/null and b/docs/manual/img/alerts-log.png differ diff --git a/docs/manual/img/all-services.png b/docs/manual/img/all-services.png new file mode 100644 index 0000000000..1a94b6bcc6 Binary files /dev/null and b/docs/manual/img/all-services.png differ diff --git a/docs/manual/img/apikey-delete-confirm.png b/docs/manual/img/apikey-delete-confirm.png new file mode 100644 index 0000000000..b805b3fa0f Binary files /dev/null and b/docs/manual/img/apikey-delete-confirm.png differ diff --git a/docs/manual/img/apikey-delete.png b/docs/manual/img/apikey-delete.png new file mode 100644 index 0000000000..837506d514 Binary files /dev/null and b/docs/manual/img/apikey-delete.png differ diff --git a/docs/manual/img/apikey-edit.png b/docs/manual/img/apikey-edit.png new file mode 100644 index 0000000000..62f2c5ebcd Binary files /dev/null and b/docs/manual/img/apikey-edit.png differ diff --git a/docs/manual/img/apikey-update.png b/docs/manual/img/apikey-update.png new file mode 100644 index 0000000000..02de5535e4 Binary files /dev/null and b/docs/manual/img/apikey-update.png differ diff --git a/docs/manual/img/apikey.png b/docs/manual/img/apikey.png new file mode 100644 index 0000000000..785a257869 Binary files /dev/null and b/docs/manual/img/apikey.png differ diff --git a/docs/manual/img/apikeys-list.png b/docs/manual/img/apikeys-list.png new file mode 100644 index 0000000000..d5a3b1fe9b Binary files /dev/null and b/docs/manual/img/apikeys-list.png differ diff --git a/docs/manual/img/architecture-1-bis.png b/docs/manual/img/architecture-1-bis.png new file mode 100644 index 0000000000..89aff27480 Binary files /dev/null and b/docs/manual/img/architecture-1-bis.png differ diff --git a/docs/manual/img/architecture-1.png b/docs/manual/img/architecture-1.png new file mode 100644 index 0000000000..7ab2243857 Binary files /dev/null and b/docs/manual/img/architecture-1.png differ diff --git a/docs/manual/img/architecture-2-bis.png b/docs/manual/img/architecture-2-bis.png new file mode 100644 index 0000000000..b8359b490f Binary files /dev/null and b/docs/manual/img/architecture-2-bis.png differ diff --git a/docs/manual/img/architecture-2.png b/docs/manual/img/architecture-2.png new file mode 100644 index 0000000000..649f47361a Binary files /dev/null and b/docs/manual/img/architecture-2.png differ diff --git a/docs/manual/img/audit-log.png b/docs/manual/img/audit-log.png new file mode 100644 index 0000000000..01f0364d56 Binary files /dev/null and b/docs/manual/img/audit-log.png differ diff --git a/docs/manual/img/auth0-settings.png b/docs/manual/img/auth0-settings.png new file mode 100644 index 0000000000..3a262be6de Binary files /dev/null and b/docs/manual/img/auth0-settings.png differ diff --git a/docs/manual/img/clevercloud-integration-1.png b/docs/manual/img/clevercloud-integration-1.png new file mode 100644 index 0000000000..c89d4c5196 Binary files /dev/null and b/docs/manual/img/clevercloud-integration-1.png differ diff --git a/docs/manual/img/clevercloud-integration-2.png b/docs/manual/img/clevercloud-integration-2.png new file mode 100644 index 0000000000..b28292f1c3 Binary files /dev/null and b/docs/manual/img/clevercloud-integration-2.png differ diff --git a/docs/manual/img/clevercloud-integration-3.png b/docs/manual/img/clevercloud-integration-3.png new file mode 100644 index 0000000000..53a7084df2 Binary files /dev/null and b/docs/manual/img/clevercloud-integration-3.png differ diff --git a/docs/manual/img/cluster-1.png b/docs/manual/img/cluster-1.png new file mode 100644 index 0000000000..ecb32065ea Binary files /dev/null and b/docs/manual/img/cluster-1.png differ diff --git a/docs/manual/img/cluster-2.png b/docs/manual/img/cluster-2.png new file mode 100644 index 0000000000..dc84eefec2 Binary files /dev/null and b/docs/manual/img/cluster-2.png differ diff --git a/docs/manual/img/cluster-3.png b/docs/manual/img/cluster-3.png new file mode 100644 index 0000000000..e7e35c744b Binary files /dev/null and b/docs/manual/img/cluster-3.png differ diff --git a/docs/manual/img/cluster-4.png b/docs/manual/img/cluster-4.png new file mode 100644 index 0000000000..0f9dbfa027 Binary files /dev/null and b/docs/manual/img/cluster-4.png differ diff --git a/docs/manual/img/cluster-5.jpg b/docs/manual/img/cluster-5.jpg new file mode 100644 index 0000000000..e301061e03 Binary files /dev/null and b/docs/manual/img/cluster-5.jpg differ diff --git a/docs/manual/img/cluster-6.png b/docs/manual/img/cluster-6.png new file mode 100644 index 0000000000..455da288c4 Binary files /dev/null and b/docs/manual/img/cluster-6.png differ diff --git a/docs/manual/img/cors.png b/docs/manual/img/cors.png new file mode 100644 index 0000000000..f08c4c17a9 Binary files /dev/null and b/docs/manual/img/cors.png differ diff --git a/docs/manual/img/create-admin-u2f.png b/docs/manual/img/create-admin-u2f.png new file mode 100644 index 0000000000..4fd2797bff Binary files /dev/null and b/docs/manual/img/create-admin-u2f.png differ diff --git a/docs/manual/img/create-admin.png b/docs/manual/img/create-admin.png new file mode 100644 index 0000000000..3d9d6168fe Binary files /dev/null and b/docs/manual/img/create-admin.png differ diff --git a/docs/manual/img/create-apikey.png b/docs/manual/img/create-apikey.png new file mode 100644 index 0000000000..fae847f371 Binary files /dev/null and b/docs/manual/img/create-apikey.png differ diff --git a/docs/manual/img/danger-zone-1-commons.png b/docs/manual/img/danger-zone-1-commons.png new file mode 100644 index 0000000000..fd99c119c3 Binary files /dev/null and b/docs/manual/img/danger-zone-1-commons.png differ diff --git a/docs/manual/img/danger-zone-10-clevercloud.png b/docs/manual/img/danger-zone-10-clevercloud.png new file mode 100644 index 0000000000..037ad74fce Binary files /dev/null and b/docs/manual/img/danger-zone-10-clevercloud.png differ diff --git a/docs/manual/img/danger-zone-11-bottom.png b/docs/manual/img/danger-zone-11-bottom.png new file mode 100644 index 0000000000..53b592cafc Binary files /dev/null and b/docs/manual/img/danger-zone-11-bottom.png differ diff --git a/docs/manual/img/danger-zone-2-whitelist-blacklist.png b/docs/manual/img/danger-zone-2-whitelist-blacklist.png new file mode 100644 index 0000000000..83a3b91378 Binary files /dev/null and b/docs/manual/img/danger-zone-2-whitelist-blacklist.png differ diff --git a/docs/manual/img/danger-zone-3-throttling.png b/docs/manual/img/danger-zone-3-throttling.png new file mode 100644 index 0000000000..58a4957975 Binary files /dev/null and b/docs/manual/img/danger-zone-3-throttling.png differ diff --git a/docs/manual/img/danger-zone-4-analytics.png b/docs/manual/img/danger-zone-4-analytics.png new file mode 100644 index 0000000000..b6504e3a2d Binary files /dev/null and b/docs/manual/img/danger-zone-4-analytics.png differ diff --git a/docs/manual/img/danger-zone-5-kafka.png b/docs/manual/img/danger-zone-5-kafka.png new file mode 100644 index 0000000000..3900436bf2 Binary files /dev/null and b/docs/manual/img/danger-zone-5-kafka.png differ diff --git a/docs/manual/img/danger-zone-6-alerts.png b/docs/manual/img/danger-zone-6-alerts.png new file mode 100644 index 0000000000..b8f542c19b Binary files /dev/null and b/docs/manual/img/danger-zone-6-alerts.png differ diff --git a/docs/manual/img/danger-zone-7-statsd.png b/docs/manual/img/danger-zone-7-statsd.png new file mode 100644 index 0000000000..df5cc3075d Binary files /dev/null and b/docs/manual/img/danger-zone-7-statsd.png differ diff --git a/docs/manual/img/danger-zone-8-auth0.png b/docs/manual/img/danger-zone-8-auth0.png new file mode 100644 index 0000000000..d3e05ab449 Binary files /dev/null and b/docs/manual/img/danger-zone-8-auth0.png differ diff --git a/docs/manual/img/danger-zone-9-mailgun.png b/docs/manual/img/danger-zone-9-mailgun.png new file mode 100644 index 0000000000..312ac5f956 Binary files /dev/null and b/docs/manual/img/danger-zone-9-mailgun.png differ diff --git a/docs/manual/img/datastores.png b/docs/manual/img/datastores.png new file mode 100644 index 0000000000..526ea7c809 Binary files /dev/null and b/docs/manual/img/datastores.png differ diff --git a/docs/manual/img/delete.png b/docs/manual/img/delete.png new file mode 100644 index 0000000000..dc594d8e0d Binary files /dev/null and b/docs/manual/img/delete.png differ diff --git a/docs/manual/img/deploy-cc-0.png b/docs/manual/img/deploy-cc-0.png new file mode 100644 index 0000000000..a965d50ea1 Binary files /dev/null and b/docs/manual/img/deploy-cc-0.png differ diff --git a/docs/manual/img/deploy-cc-1.png b/docs/manual/img/deploy-cc-1.png new file mode 100644 index 0000000000..2aa8bb705c Binary files /dev/null and b/docs/manual/img/deploy-cc-1.png differ diff --git a/docs/manual/img/deploy-cc-2.png b/docs/manual/img/deploy-cc-2.png new file mode 100644 index 0000000000..0ae38a2cde Binary files /dev/null and b/docs/manual/img/deploy-cc-2.png differ diff --git a/docs/manual/img/deploy-cc-3.png b/docs/manual/img/deploy-cc-3.png new file mode 100644 index 0000000000..fefc22354c Binary files /dev/null and b/docs/manual/img/deploy-cc-3.png differ diff --git a/docs/manual/img/deploy-cc-4-bis.png b/docs/manual/img/deploy-cc-4-bis.png new file mode 100644 index 0000000000..a973c2f851 Binary files /dev/null and b/docs/manual/img/deploy-cc-4-bis.png differ diff --git a/docs/manual/img/deploy-cc-4.png b/docs/manual/img/deploy-cc-4.png new file mode 100644 index 0000000000..a9035abf58 Binary files /dev/null and b/docs/manual/img/deploy-cc-4.png differ diff --git a/docs/manual/img/deploy-cc-5.png b/docs/manual/img/deploy-cc-5.png new file mode 100644 index 0000000000..cc3b2a9b58 Binary files /dev/null and b/docs/manual/img/deploy-cc-5.png differ diff --git a/docs/manual/img/deploy-cc-jar-0.png b/docs/manual/img/deploy-cc-jar-0.png new file mode 100644 index 0000000000..3bb53e2a2c Binary files /dev/null and b/docs/manual/img/deploy-cc-jar-0.png differ diff --git a/docs/manual/img/deploy-cc-jar-1.png b/docs/manual/img/deploy-cc-jar-1.png new file mode 100644 index 0000000000..e244081a8e Binary files /dev/null and b/docs/manual/img/deploy-cc-jar-1.png differ diff --git a/docs/manual/img/deploy-elb-0.png b/docs/manual/img/deploy-elb-0.png new file mode 100644 index 0000000000..47f176a8a2 Binary files /dev/null and b/docs/manual/img/deploy-elb-0.png differ diff --git a/docs/manual/img/deploy-elb-1.png b/docs/manual/img/deploy-elb-1.png new file mode 100644 index 0000000000..e52c64eb5f Binary files /dev/null and b/docs/manual/img/deploy-elb-1.png differ diff --git a/docs/manual/img/deploy-elb-10.png b/docs/manual/img/deploy-elb-10.png new file mode 100644 index 0000000000..614dfa9d59 Binary files /dev/null and b/docs/manual/img/deploy-elb-10.png differ diff --git a/docs/manual/img/deploy-elb-11.png b/docs/manual/img/deploy-elb-11.png new file mode 100644 index 0000000000..9b3fc8f378 Binary files /dev/null and b/docs/manual/img/deploy-elb-11.png differ diff --git a/docs/manual/img/deploy-elb-12.png b/docs/manual/img/deploy-elb-12.png new file mode 100644 index 0000000000..cef06c52f9 Binary files /dev/null and b/docs/manual/img/deploy-elb-12.png differ diff --git a/docs/manual/img/deploy-elb-13.png b/docs/manual/img/deploy-elb-13.png new file mode 100644 index 0000000000..78c531aee4 Binary files /dev/null and b/docs/manual/img/deploy-elb-13.png differ diff --git a/docs/manual/img/deploy-elb-14.png b/docs/manual/img/deploy-elb-14.png new file mode 100644 index 0000000000..69f4db325d Binary files /dev/null and b/docs/manual/img/deploy-elb-14.png differ diff --git a/docs/manual/img/deploy-elb-15.png b/docs/manual/img/deploy-elb-15.png new file mode 100644 index 0000000000..daca945f0d Binary files /dev/null and b/docs/manual/img/deploy-elb-15.png differ diff --git a/docs/manual/img/deploy-elb-16.png b/docs/manual/img/deploy-elb-16.png new file mode 100644 index 0000000000..78846f84c3 Binary files /dev/null and b/docs/manual/img/deploy-elb-16.png differ diff --git a/docs/manual/img/deploy-elb-17.png b/docs/manual/img/deploy-elb-17.png new file mode 100644 index 0000000000..a0c85b30cf Binary files /dev/null and b/docs/manual/img/deploy-elb-17.png differ diff --git a/docs/manual/img/deploy-elb-18.png b/docs/manual/img/deploy-elb-18.png new file mode 100644 index 0000000000..2494ff350c Binary files /dev/null and b/docs/manual/img/deploy-elb-18.png differ diff --git a/docs/manual/img/deploy-elb-2.png b/docs/manual/img/deploy-elb-2.png new file mode 100644 index 0000000000..157ac3849a Binary files /dev/null and b/docs/manual/img/deploy-elb-2.png differ diff --git a/docs/manual/img/deploy-elb-3.png b/docs/manual/img/deploy-elb-3.png new file mode 100644 index 0000000000..c1daab6c3b Binary files /dev/null and b/docs/manual/img/deploy-elb-3.png differ diff --git a/docs/manual/img/deploy-elb-4.png b/docs/manual/img/deploy-elb-4.png new file mode 100644 index 0000000000..0af025fa7a Binary files /dev/null and b/docs/manual/img/deploy-elb-4.png differ diff --git a/docs/manual/img/deploy-elb-5.png b/docs/manual/img/deploy-elb-5.png new file mode 100644 index 0000000000..96814636ec Binary files /dev/null and b/docs/manual/img/deploy-elb-5.png differ diff --git a/docs/manual/img/deploy-elb-6.png b/docs/manual/img/deploy-elb-6.png new file mode 100644 index 0000000000..2d27be8127 Binary files /dev/null and b/docs/manual/img/deploy-elb-6.png differ diff --git a/docs/manual/img/deploy-elb-7.png b/docs/manual/img/deploy-elb-7.png new file mode 100644 index 0000000000..60c3e63eb4 Binary files /dev/null and b/docs/manual/img/deploy-elb-7.png differ diff --git a/docs/manual/img/deploy-elb-8.png b/docs/manual/img/deploy-elb-8.png new file mode 100644 index 0000000000..a59130cd7a Binary files /dev/null and b/docs/manual/img/deploy-elb-8.png differ diff --git a/docs/manual/img/deploy-elb-9.png b/docs/manual/img/deploy-elb-9.png new file mode 100644 index 0000000000..9ff31e9409 Binary files /dev/null and b/docs/manual/img/deploy-elb-9.png differ diff --git a/docs/manual/img/discard-admin-user.png b/docs/manual/img/discard-admin-user.png new file mode 100644 index 0000000000..0bd089a115 Binary files /dev/null and b/docs/manual/img/discard-admin-user.png differ diff --git a/docs/manual/img/edit.png b/docs/manual/img/edit.png new file mode 100644 index 0000000000..ad8bac05d0 Binary files /dev/null and b/docs/manual/img/edit.png differ diff --git a/docs/manual/img/exchange-2.png b/docs/manual/img/exchange-2.png new file mode 100644 index 0000000000..2997395599 Binary files /dev/null and b/docs/manual/img/exchange-2.png differ diff --git a/docs/manual/img/exchange.png b/docs/manual/img/exchange.png new file mode 100644 index 0000000000..ba6d573f14 Binary files /dev/null and b/docs/manual/img/exchange.png differ diff --git a/docs/manual/img/first-admins-screen.png b/docs/manual/img/first-admins-screen.png new file mode 100644 index 0000000000..6f0e87d4ae Binary files /dev/null and b/docs/manual/img/first-admins-screen.png differ diff --git a/docs/manual/img/first-login.gif b/docs/manual/img/first-login.gif new file mode 100644 index 0000000000..b5f5c34045 Binary files /dev/null and b/docs/manual/img/first-login.gif differ diff --git a/docs/manual/img/first-login.png b/docs/manual/img/first-login.png new file mode 100644 index 0000000000..105d8257ce Binary files /dev/null and b/docs/manual/img/first-login.png differ diff --git a/docs/manual/img/full-export-1.png b/docs/manual/img/full-export-1.png new file mode 100644 index 0000000000..656107e08f Binary files /dev/null and b/docs/manual/img/full-export-1.png differ diff --git a/docs/manual/img/full-export-2.png b/docs/manual/img/full-export-2.png new file mode 100644 index 0000000000..becc999e15 Binary files /dev/null and b/docs/manual/img/full-export-2.png differ diff --git a/docs/manual/img/full-import-1-bis.png b/docs/manual/img/full-import-1-bis.png new file mode 100644 index 0000000000..0dfc714236 Binary files /dev/null and b/docs/manual/img/full-import-1-bis.png differ diff --git a/docs/manual/img/full-import-1.png b/docs/manual/img/full-import-1.png new file mode 100644 index 0000000000..667ffe54da Binary files /dev/null and b/docs/manual/img/full-import-1.png differ diff --git a/docs/manual/img/full-import-2.png b/docs/manual/img/full-import-2.png new file mode 100644 index 0000000000..f5cbef66bf Binary files /dev/null and b/docs/manual/img/full-import-2.png differ diff --git a/docs/manual/img/generated-admin-deleted.png b/docs/manual/img/generated-admin-deleted.png new file mode 100644 index 0000000000..99574204af Binary files /dev/null and b/docs/manual/img/generated-admin-deleted.png differ diff --git a/docs/manual/img/global-analytics.png b/docs/manual/img/global-analytics.png new file mode 100644 index 0000000000..ad708affe4 Binary files /dev/null and b/docs/manual/img/global-analytics.png differ diff --git a/docs/manual/img/go-to-admins.png b/docs/manual/img/go-to-admins.png new file mode 100644 index 0000000000..eb8d815e3b Binary files /dev/null and b/docs/manual/img/go-to-admins.png differ diff --git a/docs/manual/img/go-to-danger-zone.png b/docs/manual/img/go-to-danger-zone.png new file mode 100644 index 0000000000..68f71a3a20 Binary files /dev/null and b/docs/manual/img/go-to-danger-zone.png differ diff --git a/docs/manual/img/home-page.png b/docs/manual/img/home-page.png new file mode 100644 index 0000000000..5ad67786b2 Binary files /dev/null and b/docs/manual/img/home-page.png differ diff --git a/docs/manual/img/jwt-verif-capture.png b/docs/manual/img/jwt-verif-capture.png new file mode 100644 index 0000000000..b56419cac6 Binary files /dev/null and b/docs/manual/img/jwt-verif-capture.png differ diff --git a/docs/manual/img/jwt-verif-global-verifier.png b/docs/manual/img/jwt-verif-global-verifier.png new file mode 100644 index 0000000000..85b10ab8eb Binary files /dev/null and b/docs/manual/img/jwt-verif-global-verifier.png differ diff --git a/docs/manual/img/jwt-verif-global-verifiers.png b/docs/manual/img/jwt-verif-global-verifiers.png new file mode 100644 index 0000000000..ab8c23a948 Binary files /dev/null and b/docs/manual/img/jwt-verif-global-verifiers.png differ diff --git a/docs/manual/img/jwt-verif-incookie.png b/docs/manual/img/jwt-verif-incookie.png new file mode 100644 index 0000000000..59f1eaee2e Binary files /dev/null and b/docs/manual/img/jwt-verif-incookie.png differ diff --git a/docs/manual/img/jwt-verif-inheader.png b/docs/manual/img/jwt-verif-inheader.png new file mode 100644 index 0000000000..239e0b7c8d Binary files /dev/null and b/docs/manual/img/jwt-verif-inheader.png differ diff --git a/docs/manual/img/jwt-verif-inquery.png b/docs/manual/img/jwt-verif-inquery.png new file mode 100644 index 0000000000..adcbd600a1 Binary files /dev/null and b/docs/manual/img/jwt-verif-inquery.png differ diff --git a/docs/manual/img/jwt-verif-ref.png b/docs/manual/img/jwt-verif-ref.png new file mode 100644 index 0000000000..106ede046c Binary files /dev/null and b/docs/manual/img/jwt-verif-ref.png differ diff --git a/docs/manual/img/jwt-verif-resign.png b/docs/manual/img/jwt-verif-resign.png new file mode 100644 index 0000000000..583c8bd1de Binary files /dev/null and b/docs/manual/img/jwt-verif-resign.png differ diff --git a/docs/manual/img/jwt-verif-signing-1.png b/docs/manual/img/jwt-verif-signing-1.png new file mode 100644 index 0000000000..81fe7f9a62 Binary files /dev/null and b/docs/manual/img/jwt-verif-signing-1.png differ diff --git a/docs/manual/img/jwt-verif-signing-2.png b/docs/manual/img/jwt-verif-signing-2.png new file mode 100644 index 0000000000..0d168f9a2b Binary files /dev/null and b/docs/manual/img/jwt-verif-signing-2.png differ diff --git a/docs/manual/img/jwt-verif-transform.png b/docs/manual/img/jwt-verif-transform.png new file mode 100644 index 0000000000..133f5ac8ba Binary files /dev/null and b/docs/manual/img/jwt-verif-transform.png differ diff --git a/docs/manual/img/jwt-verif-verify.png b/docs/manual/img/jwt-verif-verify.png new file mode 100644 index 0000000000..c8411109ba Binary files /dev/null and b/docs/manual/img/jwt-verif-verify.png differ diff --git a/docs/manual/img/kubernetes-daikoku-integration-enabled.png b/docs/manual/img/kubernetes-daikoku-integration-enabled.png new file mode 100644 index 0000000000..b8a0b803bb Binary files /dev/null and b/docs/manual/img/kubernetes-daikoku-integration-enabled.png differ diff --git a/docs/manual/img/kubernetes-daikoku-integration-token.png b/docs/manual/img/kubernetes-daikoku-integration-token.png new file mode 100644 index 0000000000..661a86daf9 Binary files /dev/null and b/docs/manual/img/kubernetes-daikoku-integration-token.png differ diff --git a/docs/manual/img/login-auth0.png b/docs/manual/img/login-auth0.png new file mode 100644 index 0000000000..512ba1d713 Binary files /dev/null and b/docs/manual/img/login-auth0.png differ diff --git a/docs/manual/img/login-page.png b/docs/manual/img/login-page.png new file mode 100644 index 0000000000..2bfff1feff Binary files /dev/null and b/docs/manual/img/login-page.png differ diff --git a/docs/manual/img/models-apikey.png b/docs/manual/img/models-apikey.png new file mode 100644 index 0000000000..da3dff280d Binary files /dev/null and b/docs/manual/img/models-apikey.png differ diff --git a/docs/manual/img/models-group.png b/docs/manual/img/models-group.png new file mode 100644 index 0000000000..f40b69ff2a Binary files /dev/null and b/docs/manual/img/models-group.png differ diff --git a/docs/manual/img/models-service.png b/docs/manual/img/models-service.png new file mode 100644 index 0000000000..5017a00ae6 Binary files /dev/null and b/docs/manual/img/models-service.png differ diff --git a/docs/manual/img/mtls-arch-1.jpg b/docs/manual/img/mtls-arch-1.jpg new file mode 100644 index 0000000000..0e9adc85d6 Binary files /dev/null and b/docs/manual/img/mtls-arch-1.jpg differ diff --git a/docs/manual/img/mtls-arch-2.jpg b/docs/manual/img/mtls-arch-2.jpg new file mode 100644 index 0000000000..54c780f827 Binary files /dev/null and b/docs/manual/img/mtls-arch-2.jpg differ diff --git a/docs/manual/img/mtls-cert-client-backend-1.png b/docs/manual/img/mtls-cert-client-backend-1.png new file mode 100644 index 0000000000..c2c0dbe2e9 Binary files /dev/null and b/docs/manual/img/mtls-cert-client-backend-1.png differ diff --git a/docs/manual/img/mtls-cert-server-frontend-1.png b/docs/manual/img/mtls-cert-server-frontend-1.png new file mode 100644 index 0000000000..4e5374427d Binary files /dev/null and b/docs/manual/img/mtls-cert-server-frontend-1.png differ diff --git a/docs/manual/img/mtls-ff-1.png b/docs/manual/img/mtls-ff-1.png new file mode 100644 index 0000000000..154a6bf590 Binary files /dev/null and b/docs/manual/img/mtls-ff-1.png differ diff --git a/docs/manual/img/mtls-ff-2.png b/docs/manual/img/mtls-ff-2.png new file mode 100644 index 0000000000..8a944482a8 Binary files /dev/null and b/docs/manual/img/mtls-ff-2.png differ diff --git a/docs/manual/img/mtls-ff-3.png b/docs/manual/img/mtls-ff-3.png new file mode 100644 index 0000000000..97636099d2 Binary files /dev/null and b/docs/manual/img/mtls-ff-3.png differ diff --git a/docs/manual/img/mtls-service-1.png b/docs/manual/img/mtls-service-1.png new file mode 100644 index 0000000000..ebe2b630fc Binary files /dev/null and b/docs/manual/img/mtls-service-1.png differ diff --git a/docs/manual/img/mtls-va-1.png b/docs/manual/img/mtls-va-1.png new file mode 100644 index 0000000000..632bce82ab Binary files /dev/null and b/docs/manual/img/mtls-va-1.png differ diff --git a/docs/manual/img/mtls-va-ref-1.png b/docs/manual/img/mtls-va-ref-1.png new file mode 100644 index 0000000000..6f833adbdb Binary files /dev/null and b/docs/manual/img/mtls-va-ref-1.png differ diff --git a/docs/manual/img/new-service-canary.png b/docs/manual/img/new-service-canary.png new file mode 100644 index 0000000000..c616394089 Binary files /dev/null and b/docs/manual/img/new-service-canary.png differ diff --git a/docs/manual/img/new-service-client.png b/docs/manual/img/new-service-client.png new file mode 100644 index 0000000000..7e7b65bbc2 Binary files /dev/null and b/docs/manual/img/new-service-client.png differ diff --git a/docs/manual/img/new-service-flags.png b/docs/manual/img/new-service-flags.png new file mode 100644 index 0000000000..8de5695e52 Binary files /dev/null and b/docs/manual/img/new-service-flags.png differ diff --git a/docs/manual/img/new-service-flags2.png b/docs/manual/img/new-service-flags2.png new file mode 100644 index 0000000000..1a9190ebbf Binary files /dev/null and b/docs/manual/img/new-service-flags2.png differ diff --git a/docs/manual/img/new-service-headers.png b/docs/manual/img/new-service-headers.png new file mode 100644 index 0000000000..11ddae313c Binary files /dev/null and b/docs/manual/img/new-service-headers.png differ diff --git a/docs/manual/img/new-service-healthcheck.png b/docs/manual/img/new-service-healthcheck.png new file mode 100644 index 0000000000..f80d072c2d Binary files /dev/null and b/docs/manual/img/new-service-healthcheck.png differ diff --git a/docs/manual/img/new-service-meta.png b/docs/manual/img/new-service-meta.png new file mode 100644 index 0000000000..331d8c3fb1 Binary files /dev/null and b/docs/manual/img/new-service-meta.png differ diff --git a/docs/manual/img/new-service-patterns.png b/docs/manual/img/new-service-patterns.png new file mode 100644 index 0000000000..2cd9738672 Binary files /dev/null and b/docs/manual/img/new-service-patterns.png differ diff --git a/docs/manual/img/new-service-patterns_2.png b/docs/manual/img/new-service-patterns_2.png new file mode 100644 index 0000000000..a47b6c92cd Binary files /dev/null and b/docs/manual/img/new-service-patterns_2.png differ diff --git a/docs/manual/img/private-sessions.png b/docs/manual/img/private-sessions.png new file mode 100644 index 0000000000..6f3dcd8d7f Binary files /dev/null and b/docs/manual/img/private-sessions.png differ diff --git a/docs/manual/img/push-to-elastic.png b/docs/manual/img/push-to-elastic.png new file mode 100644 index 0000000000..88813c1d10 Binary files /dev/null and b/docs/manual/img/push-to-elastic.png differ diff --git a/docs/manual/img/register-admin-button.png b/docs/manual/img/register-admin-button.png new file mode 100644 index 0000000000..16d2508eb0 Binary files /dev/null and b/docs/manual/img/register-admin-button.png differ diff --git a/docs/manual/img/scripts-1.png b/docs/manual/img/scripts-1.png new file mode 100644 index 0000000000..85069f288e Binary files /dev/null and b/docs/manual/img/scripts-1.png differ diff --git a/docs/manual/img/scripts-2.png b/docs/manual/img/scripts-2.png new file mode 100644 index 0000000000..772d45b901 Binary files /dev/null and b/docs/manual/img/scripts-2.png differ diff --git a/docs/manual/img/sec-com-signing-2-bis.png b/docs/manual/img/sec-com-signing-2-bis.png new file mode 100644 index 0000000000..223fef6749 Binary files /dev/null and b/docs/manual/img/sec-com-signing-2-bis.png differ diff --git a/docs/manual/img/sec-com-signing-2.png b/docs/manual/img/sec-com-signing-2.png new file mode 100644 index 0000000000..6d88f6cbac Binary files /dev/null and b/docs/manual/img/sec-com-signing-2.png differ diff --git a/docs/manual/img/sec-com-signing-bis.png b/docs/manual/img/sec-com-signing-bis.png new file mode 100644 index 0000000000..8ebcd37c6f Binary files /dev/null and b/docs/manual/img/sec-com-signing-bis.png differ diff --git a/docs/manual/img/sec-com-signing.png b/docs/manual/img/sec-com-signing.png new file mode 100644 index 0000000000..b724a9237f Binary files /dev/null and b/docs/manual/img/sec-com-signing.png differ diff --git a/docs/manual/img/service-analytics.png b/docs/manual/img/service-analytics.png new file mode 100644 index 0000000000..9fa513b6c2 Binary files /dev/null and b/docs/manual/img/service-analytics.png differ diff --git a/docs/manual/img/service-flags-3.png b/docs/manual/img/service-flags-3.png new file mode 100644 index 0000000000..6e5ba5d511 Binary files /dev/null and b/docs/manual/img/service-flags-3.png differ diff --git a/docs/manual/img/service-flags.png b/docs/manual/img/service-flags.png new file mode 100644 index 0000000000..d22178f9d5 Binary files /dev/null and b/docs/manual/img/service-flags.png differ diff --git a/docs/manual/img/service-groups-add.png b/docs/manual/img/service-groups-add.png new file mode 100644 index 0000000000..ce33f190c0 Binary files /dev/null and b/docs/manual/img/service-groups-add.png differ diff --git a/docs/manual/img/service-groups-create.png b/docs/manual/img/service-groups-create.png new file mode 100644 index 0000000000..1b78ce7b26 Binary files /dev/null and b/docs/manual/img/service-groups-create.png differ diff --git a/docs/manual/img/service-groups-created.png b/docs/manual/img/service-groups-created.png new file mode 100644 index 0000000000..f7d56ca710 Binary files /dev/null and b/docs/manual/img/service-groups-created.png differ diff --git a/docs/manual/img/service-groups-delete-confirm.png b/docs/manual/img/service-groups-delete-confirm.png new file mode 100644 index 0000000000..28f404c4c3 Binary files /dev/null and b/docs/manual/img/service-groups-delete-confirm.png differ diff --git a/docs/manual/img/service-groups-delete.png b/docs/manual/img/service-groups-delete.png new file mode 100644 index 0000000000..760cb7557b Binary files /dev/null and b/docs/manual/img/service-groups-delete.png differ diff --git a/docs/manual/img/service-groups-edit.png b/docs/manual/img/service-groups-edit.png new file mode 100644 index 0000000000..28b2de539a Binary files /dev/null and b/docs/manual/img/service-groups-edit.png differ diff --git a/docs/manual/img/service-groups-new.png b/docs/manual/img/service-groups-new.png new file mode 100644 index 0000000000..f1bff4bbf7 Binary files /dev/null and b/docs/manual/img/service-groups-new.png differ diff --git a/docs/manual/img/service-groups-update.png b/docs/manual/img/service-groups-update.png new file mode 100644 index 0000000000..32cd142833 Binary files /dev/null and b/docs/manual/img/service-groups-update.png differ diff --git a/docs/manual/img/service-groups.png b/docs/manual/img/service-groups.png new file mode 100644 index 0000000000..bc0ea3e01e Binary files /dev/null and b/docs/manual/img/service-groups.png differ diff --git a/docs/manual/img/service-healthcheck.png b/docs/manual/img/service-healthcheck.png new file mode 100644 index 0000000000..e299d0db35 Binary files /dev/null and b/docs/manual/img/service-healthcheck.png differ diff --git a/docs/manual/img/service-live-stats.png b/docs/manual/img/service-live-stats.png new file mode 100644 index 0000000000..e4277aa41a Binary files /dev/null and b/docs/manual/img/service-live-stats.png differ diff --git a/docs/manual/img/settings-menu-groups.png b/docs/manual/img/settings-menu-groups.png new file mode 100644 index 0000000000..d1607da224 Binary files /dev/null and b/docs/manual/img/settings-menu-groups.png differ diff --git a/docs/manual/img/settings-menu.png b/docs/manual/img/settings-menu.png new file mode 100644 index 0000000000..f4ae289970 Binary files /dev/null and b/docs/manual/img/settings-menu.png differ diff --git a/docs/manual/img/sidebar-all-services.png b/docs/manual/img/sidebar-all-services.png new file mode 100644 index 0000000000..18ddc67ace Binary files /dev/null and b/docs/manual/img/sidebar-all-services.png differ diff --git a/docs/manual/img/sidebar-apikeys.png b/docs/manual/img/sidebar-apikeys.png new file mode 100644 index 0000000000..7cc11c0a31 Binary files /dev/null and b/docs/manual/img/sidebar-apikeys.png differ diff --git a/docs/manual/img/small-otoroshi-logo-xmas.png b/docs/manual/img/small-otoroshi-logo-xmas.png new file mode 100644 index 0000000000..44812ccc85 Binary files /dev/null and b/docs/manual/img/small-otoroshi-logo-xmas.png differ diff --git a/docs/manual/img/small-otoroshi-logo.png b/docs/manual/img/small-otoroshi-logo.png new file mode 100644 index 0000000000..fc393e3edc Binary files /dev/null and b/docs/manual/img/small-otoroshi-logo.png differ diff --git a/docs/manual/img/snow-monkey-faults.png b/docs/manual/img/snow-monkey-faults.png new file mode 100644 index 0000000000..ff53cac7cb Binary files /dev/null and b/docs/manual/img/snow-monkey-faults.png differ diff --git a/docs/manual/img/snow-monkey-outages.png b/docs/manual/img/snow-monkey-outages.png new file mode 100644 index 0000000000..4381ff45fb Binary files /dev/null and b/docs/manual/img/snow-monkey-outages.png differ diff --git a/docs/manual/img/snow-monkey-settings.png b/docs/manual/img/snow-monkey-settings.png new file mode 100644 index 0000000000..7dcde5873c Binary files /dev/null and b/docs/manual/img/snow-monkey-settings.png differ diff --git a/docs/manual/img/snow-monkey-start.png b/docs/manual/img/snow-monkey-start.png new file mode 100644 index 0000000000..5e0be102fd Binary files /dev/null and b/docs/manual/img/snow-monkey-start.png differ diff --git a/docs/manual/img/snow-monkey.png b/docs/manual/img/snow-monkey.png new file mode 100644 index 0000000000..06742241fb Binary files /dev/null and b/docs/manual/img/snow-monkey.png differ diff --git a/docs/manual/img/ssl.png b/docs/manual/img/ssl.png new file mode 100644 index 0000000000..e849eeb1f7 Binary files /dev/null and b/docs/manual/img/ssl.png differ diff --git a/docs/manual/img/ssl2.png b/docs/manual/img/ssl2.png new file mode 100644 index 0000000000..5698db4e55 Binary files /dev/null and b/docs/manual/img/ssl2.png differ diff --git a/docs/manual/img/tls13.png b/docs/manual/img/tls13.png new file mode 100644 index 0000000000..4c53aaa632 Binary files /dev/null and b/docs/manual/img/tls13.png differ diff --git a/docs/manual/index.html b/docs/manual/index.html new file mode 100644 index 0000000000..26518416d4 --- /dev/null +++ b/docs/manual/index.html @@ -0,0 +1,486 @@ + + + + +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.0-rc.2/otoroshi.jar'
+java -jar otoroshi.jar
+
+

or using docker

+
docker run -p "8080:8080" maif/otoroshi:1.5.0-rc.2
+
+

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

+

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]((https://github.com/MAIF/otoroshi/CHANGELOG.md)

+

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/integrations/analytics.html b/docs/manual/integrations/analytics.html new file mode 100644 index 0000000000..445494e20d --- /dev/null +++ b/docs/manual/integrations/analytics.html @@ -0,0 +1,467 @@ + + + + +Analytics · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Analytics

+

Each action and request on Otoroshi creates events that can be sent outside of Otoroshi for further usage. Those events can be sent using a webhook and/or through a Kafka topic.

+

Push events to Elasticsearch

Warning
+

Otoroshi supports only Elasticsearch versions under 7.0

+

You can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from settings (cog icon) / Danger Zone and expand the Analytics: Elastic cluster (write) section.

+
+

Read events from Elasticsearch

+

You can use elastic search to store otoroshi events. To do this you have to configure the access to elasticsearch from settings (cog icon) / Danger Zone and expand the Analytics: Elastic dashboard datasource (read) section.

+
+

Push events to WebHooks

+

Go to settings (cog icon) / Danger Zone and expand the Analytics: Webhooks section.

+
+

Here you can configure the URL of the webhook and its headers if needed.

+

Push events to Kafka

+

Events can also be sent through a Kafka topic. Go to settings (cog icon) / Danger Zone and expand the Analytics: Kafka section.

+
+

Fill the form, default values for topic names are :

+
    +
  • otoroshi-alerts
  • +
  • otoroshi-analytics
  • +
  • otoroshi-audits
  • +
Warning
+

If you use trustore/keystore to access your kafka instances, the paths should be absolute and refers to host paths. You can also choose a client certificate from otoroshi for client authentication.

+ +
+ +
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/integrations/clevercloud.html b/docs/manual/integrations/clevercloud.html new file mode 100644 index 0000000000..06db0fb000 --- /dev/null +++ b/docs/manual/integrations/clevercloud.html @@ -0,0 +1,438 @@ + + + + +Clever Cloud · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Clever Cloud

+

Otoroshi provides an integration with Clever Cloud to create easily services based on application deployed on your Clever Cloud account. Go to settings (cog icon) / Danger Zone and expand the CleverCloud settings section.

+
+

Fill the form with your CleverCloud credentials (https://www.clever-cloud.com/doc/clever-cloud-apis/cc-api/) and your CleverCloud organization id.

+

Once it’s done, you will see a new menu in the side bar.

+
+

If you click on it, you’ll see a page listing all your apps deployed on Clever Cloud with buttons to create new services with the app as the target.

+
+

You will also see a new button in the Target section of services to attach Clever Cloud applications as target for a service.

+
+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/integrations/index.html b/docs/manual/integrations/index.html new file mode 100644 index 0000000000..d0c91e49f0 --- /dev/null +++ b/docs/manual/integrations/index.html @@ -0,0 +1,429 @@ + + + + +Third party Integrations · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Third party Integrations

+

Otoroshi provides some settings to interact with some third party systems.

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/integrations/mailgun.html b/docs/manual/integrations/mailgun.html new file mode 100644 index 0000000000..c0904775b7 --- /dev/null +++ b/docs/manual/integrations/mailgun.html @@ -0,0 +1,449 @@ + + + + +Mailgun · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

Mailgun

+

If you want to receive Otoroshi alert by emails, you have to configure Otoroshi with your Mailgun credentials. Go to settings (cog icon) / Danger Zone and expand the Mailgun settings section.

+
+

Fill the form with provided information on the domain informations page on Mailgun located at https://app.mailgun.com/app/domains/my.domain.

+

Then, expand the Alert settings section and add email addresses separated by comma in the Alert emails field. Don’t forget to save.

+
+

Mailjet

+

Otoroshi also supports Mailjet. Just select Mailjet in Mailer settings type and fill the requested fields.

+ +
+
+ +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/integrations/statsd.html b/docs/manual/integrations/statsd.html new file mode 100644 index 0000000000..7165418273 --- /dev/null +++ b/docs/manual/integrations/statsd.html @@ -0,0 +1,432 @@ + + + + +StatsD / Datadog · Otoroshi + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+
+ + + +
+
+

StatsD / Datadog

+

Otoroshi provides a StatsD integration to monitor some technical metrics across all your Otoroshi instances. Go to settings (cog icon) / Danger Zone and expand the Statsd settings section.

+
+

Add the host and port of the Statsd agent on your system. If you’re using Datadog, don’t forget to check the Datadog switch.

+ +
+
+
+
+ +
+
+ +
+ +
+ + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/docs/manual/js/cc.js b/docs/manual/js/cc.js new file mode 100644 index 0000000000..de76ca7b4e --- /dev/null +++ b/docs/manual/js/cc.js @@ -0,0 +1,145 @@ +$(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/groups.js b/docs/manual/js/groups.js new file mode 100644 index 0000000000..0e43fc84b8 --- /dev/null +++ b/docs/manual/js/groups.js @@ -0,0 +1,179 @@ +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); + + // http://www.w3schools.com/js/js_cookies.asp + function setCookie(cname,cvalue,exdays) { + if(!exdays) exdays = 365; + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = "expires=" + d.toGMTString(); + document.cookie = cname + "=" + encodeURIComponent(cvalue) + ";" + expires + ";path=/"; + } + + // http://www.w3schools.com/js/js_cookies.asp + function getCookie(cname) { + var name = cname + "="; + var decodedCookie = decodeURIComponent(document.cookie); + var ca = decodedCookie.split(';'); + for(var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length, c.length); + } + } + return ""; + } + + $("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: + for (var i = 0; i < catalog[supergroup].length; i++) { + var peer = catalog[supergroup][i]; + 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); + } + }); + }); + + for (var i = 0; i < groupChangeListeners.length; i++) { + groupChangeListeners[i](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) { + var classAttribute = elem.next("dd").find("pre").attr("class"); + if (classAttribute) { + var currentClasses = classAttribute.split(' '); + var regex = new RegExp("^group-.*"); + for(var i = 0; i < currentClasses.length; i++) { + if(regex.test(currentClasses[i])) { + return currentClasses[i]; + } + } + } + + // 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 new file mode 100644 index 0000000000..52d231ecfb --- /dev/null +++ b/docs/manual/js/magellan.js @@ -0,0 +1,25 @@ +$(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/page.js b/docs/manual/js/page.js new file mode 100644 index 0000000000..b106d14524 --- /dev/null +++ b/docs/manual/js/page.js @@ -0,0 +1,59 @@ +$(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('