Deprecated
The initial Authorino PoC in Ruby is now deprecated. We have a brand new repo where we've kicked-off our Go lang implementation: 3scale-labs/authorino.
Authorino is an AuthN/AuthZ broker that implements Envoy’s external authorization gRPC protocol. It adds protection to your cloud-native APIs with:
- User authentication (OIDC, user/passwd, mTLS)
- Ad-hoc metadata addition to the authorization payload (user info, resource metadata, web hooks)
- Authorization policy enforcement (built-in and external authorization services, JWT claims, OPA, Keycloak)
Authorino complies with the 3scale Ostia architecture.
Current stage: Proof of Concept
┌────────────┐ ┌─────┐ ┌─────────┐ ┌────────┐
│API consumer│ │Envoy│ │Authorino│ │Upstream│
└─────┬──────┘ └──┬──┘ └────┬────┘ └───┬────┘
│ 1. HTTP request │ │ │
│ ──────────────────>│ │ │
│ │ 2. gRPC │ │
│ │─────────────────>│ │
│ │ │ │
│ │ ────┐ │
│ │ │ 3. Verify identity │
│ │ <───┘ │
│ │ │ │
│ │ ────┐ │
│ │ │ 4. Add metadata │
│ │ <───┘ │
│ │ │ │
│ │ ────┐
│ │ │ 5. Enforce policies
│ │ <───┘
│ │ 6. OK │ │
│ │<─────────────────│ │
│ │ │ │
│ │ 7. HTTP request │
│ │───────────────────────────────────────────>
│ │ │ │
│ │ 8. HTTP response │
│ <───────────────────────────────────────────────────────────────
┌─────┴──────┐ ┌──┴──┐ ┌────┴────┐ ┌───┴────┐
│API consumer│ │Envoy│ │Authorino│ │Upstream│
└────────────┘ └─────┘ └─────────┘ └────────┘
- An API consumer sends a request to the Envoy endpoint, including the
Authorization
andHost
HTTP headers - The Envoy proxy establishes fast gRPC connection with Authorino, carrying data of the HTTP request
- Identity verification step - Authorino verifies the identity of the the original requestor, where at least one authentication method/identity provider should answer
- Ad-hoc authorization metadata step - Authorino integrates external sources to add metadata to the authorization payload, such as user info, attributes of the requested resource and payload-mutating web hooks
- Policy enforcement step - Authorino dispatches authorization policy evaluation to one or more configured Policy Decision Points (PDP)
- Authorino and Envoy settle the authorization protocol with either a
200 OK
,403 Forbidden
or404 Not found
response - If authorized, Envoy redirects to the requested Upstream
- The Upstream serves the requested resource
The three Authorino's core steps are depicted in the diagram, respectively, as 3, 4 and 5 in the overall flow. These steps rely on well-established industry standards and protocols, such as OpenID Connect (OIDC), User-Managed Access (UMA), Open Policy Agent (OPA) and mutual Transport Layer Security (mTLS), and enable API developers to add API security through configuration by mixing and combining settings to external services that implement such standards. Authorino enforces authentication and authorization to the API requests based on that single file configuration.
Identity verification can be, for example, verifying a provided JSON Web Token (JWT) previously issued by an OIDC-compliant authentication server and provided in the Authorization
header of the HTTP request. Authorino will auto-discover the OIDC configuration from the settings, verify the token signature and validity in time.
Ad-hoc authorization metadata can be the fetching of OIDC user info (based on the same configuration used for the identity before) and/or about fecthing resource data from a UMA-compliant server that knows about the resources.
Policy enforcement is where Authorino connects to one or more authorization policy evaluation services (or Policy Decision Points (PDP)) that will ultimately decide on whether the HTTP request should be authorized or not, given the known gathered information about the identity, the origin of the request, the requested resource and, of course, the configured policies.
Identity verification and Ad-hoc authorization metadata steps add info for the Policy enforcement, meaning API developers can write authorization policies trusting on information available about the requestor's identity (a decoded JWT, for example) and on the metadata added ad-hoc to the authorization payload (e.g. specific user info or data about the requested resource). Of course, if Authorino fails to verify the user's identity in the Identity verification step, the request is rejected without further development of the other two steps.
Once ready, Authorino will support at least 3 different authentication methods (i.e., OIDC, user/passwd and mTLS), plus ad-hoc additions to the authorization payload (e.g., user info, resource metadata, web hooks), and combination of multiple authorization services (JWT claims, OPA, Keycloak). Authorino will also handle caching of user credentials, permissions, revocations.
Here's a list of features related to each of Authorino's 3 core steps and supporting features.
- Features listed as "PoC" mean they are already implemented and ready to use in the current stage of Authorino, which is still in proof of concept.
- "Planned" are the features that are part of the original proposal of Authorino but not yet in PoC.
- "In analysis" are suggested features that may require extra effort to be implemented and therefore are still being analyzed regarding viability or design.
Feature | Stage | |
---|---|---|
Identity verification | OpenID Connect (OIDC) | PoC |
Basic auth (user/passwd) | Planned | |
mTLS | Planned | |
HMAC | In analysis | |
Ad-hoc authorization metadata | OIDC user info | PoC |
UMA-protected resource attributes | PoC | |
Web hooks | In analysis | |
Policy enforcement | OPA inline Rego policies | PoC |
OPA simple pattern matching | In analysis | |
Keycloak (UMA-compliant Authorization API) | In analysis | |
JWT claims | Planned | |
Caching | OIDC and UMA configs | PoC |
JSON Web Ket Sets (JWKS) | PoC | |
Revoked access tokens | Planned | |
Resource data | Planned | |
Authorization policies | PoC | |
Repeated requests | In analysis | |
Multitenancy (multiple upstreams) | PoC |
Authorino automatically discovers OIDC configurations for the registered issuers and verifies JSON Web Tokens (JWTs) provided in the Authorization
header by the API consumers on every request.
Authorino also automatically fetches the JSON Web Key Sets (JWKS) used to verify the JWTs, matching the kid
stated in the JWT header (i.e., support to easy key rotation).
In general, OIDC confgurations are essencially used in the identity verification and in the ad-hoc authorization metadata steps of Authorino. The decoded JWTs and fetched user info are passed in the authorization payload to the third step, i.e., policy enforcement.
┌─────────┐ ┌───────────┐
│Authorino│ │OIDC Issuer│
└────┬────┘ └─────┬─────┘
│ OIDC discovery │
│────────────────────────>│
│ Well-Known config │
(cache) │<────────────────────────│
│ │
│ Req OIDC certs │
│────────────────────────>│
│ JWKS │
(cache) │<────────────────────────│
│ │
────┐ │
│ Verify JWT signature│
<───┘ │
│ │
────┐ │
│ Validate JWT │
<───┘ │
┌────┴────┐ ┌─────┴─────┐
│Authorino│ │OIDC Issuer│
└─────────┘ └───────────┘
User-Managed Access (UMA) is an OAuth-based protocol for resource owners to allow other users to access their resources. Since the UMA-compliant server is expected to know about the resources, Authorino includes a client that fetches resource data from the server and adds that as metadata of the authorization payload.
This enables the implementation of Attribute-Based Access Control (ABAC) policies using attributes of the resources. These attributes can be, e.g., the owner of the resource (say, to match with the requestor identity) or any business-level attributes stored in the UMA-compliant server.
A UMA-compliant server can be an external authorization server (e.g., Keycloak) where the protected resources are registered or it can be the upstream API itself (as long as it implements the UMA protocol, with initial authentication by client_credentials
grant to exchange for a Protected API Token (PAT)).
┌─────────┐ ┌──────────┐
│Authorino│ │UMA server│
└────┬────┘ └────┬─────┘
│ UMA Discovery │
│───────────────────────────>
│ Well-Known config │
(cache) │<───────────────────────────
│ │
│ Request PAT │
│───────────────────────────>
│ PAT │
│<───────────────────────────
│ │
│Query resources (?uri=path)│
│───────────────────────────>
│ [...resources] │
│<───────────────────────────
│ │
│ GET resource │
│───────────────────────────>
│ Resource data │
│<───────────────────────────
┌────┴────┐ ┌────┴─────┐
│Authorino│ │UMA server│
└─────────┘ └──────────┘
It's important to notice that Authorino does NOT manage resources in the UMA-compliant server. As shown in the flow above, Authorino's UMA client is only to fetch data about the requested resources. Authorino exchanges client credentials for a Protected API Token (PAT), then queries for resources whose URI match the path of the HTTP request (as passed to Authorino by the Envoy proxy) and fecthes data of each macthing resource.
The resources data is added as metadata of the authorization payload and passed in the input for the configured Policy Decision Points (e.g., an OPA authorization service). All resources returned by the UMA-compliant server in the query by URI are passed along. They are available in the PDPs' input as input.context.metadata.uma => Array
.
You can model authorization policies in Rego language and add them as part of the configuration of your protected APIs. Authorino will keep track of changes to the policies and automatically register them to the OPA server.
┌─────────┐ ┌───┐
│Authorino│ │OPA│
└────┬────┘ └─┬─┘
· ·
Boot-time: │ Register policy │
│───────────────────────>│
│<───────────────────────│
│ │
· ·
Request-time: │Get document with input │
│───────────────────────>│
│ │
│ ────┐
│ │ Evaluate policy
│ <───┘
│ │
│ 200 OK │
│<───────────────────────│
┌────┴────┐ ┌─┴─┐
│Authorino│ │OPA│
└─────────┘ └───┘
There are 2 main use cases for Authorino:
- A. protecting APIs
- B. protecting resources and scopes of the APIM system
We are currently working on the features to support use case A and, at the same time, planning for soon having Authorino configured and deployed with Red Hat 3scale to support use case B. The latter will allow API providers to configure access control over resources of the API management system in the same fashion they do for their managed APIs.
To use Authorino to protect your APIs with OIDC and OPA, please consider the following requirements and deployment options.
- At least one upstream API (i.e., the API you want to protect)
- Envoy proxy managing the HTTP connections to the upstream API and configured with the External Authorization Filter pointing to Authorino (default port: 50051).
- For OpenID Connect, an authority that can issue JWTs
- For UMA-protected resource data, a UMA-compliant server
- OPA server (default port: 8181)
Authorino configuration is one YAML file and a couple of environment variables. The structure of the YAML config is something like the following:
<upstream-host>:<port>:
enabled: true/false
identity: [] # -- list of authentication modes and settings (e.g. `oidc`)
metadata: [] # -- list of metadata sources (e.g. `userinfo`, `uma`)
authorization: [] # -- list of PDPs/authorization services and settings (e.g. `opa`)
<other-upstream>:<port>:
...
A more concrete example of Authorino's config.yml
file can be found here.
And here's the list of supported environment variables when running Authorino:
CONFIG |
Path to the Authorino YAML config file |
PORT |
TCP Port that Authorino will listen for gRPC call from the Envoy proxy (default: 50051) |
LOG_LEVEL |
Ruby log level (default: info, ref) |
For the inline Rego policies in your OPA authorization config, the following objects are available in every document:
http_request
: attributes of the HTTP request (e.g., host, path, headers, etc) as passed by Envoy to Authorinoidentity
: whatever is resolved from the "identity" section of Authorino config, e.g. a decoded JWT of an OIDC authenticationmetadata
: whatever is resolved from the "metadata" section of Authorino config, e.g. OIDC user info, resource data fetched from a UMA-compliant serverpath
(Array): just an array of each segment ofhttp_request.path
to ease writing of rules with comparisson expressions using the requested path.
docker run -v './path/to/config.yml:/usr/src/app/config.yml' -p '50051:50051' 3scale/authorino:latest
A set of YAMLs exemplifying Authorino deployed to Kubernetes with an OPA PDP sidecar can be found here. We recommend storing Authorino's config.yml
in a ConfigMap
(example). Follow by creating Authorino's Deployment
and Service
.
Usually the entire order of deployment goes as follows:
- Upstream API(s)
- Policy Decision Point (PDP) service (e.g. OPA server) – can be deployed as an Authorino sidecard as well, like in the example provided
- Authorino
ConfigMap
Deployment
Service
- Envoy
ConfigMap
Deployment
Service
Ingress
(and ingress controller) or OpenshiftRoute
Try the example on your Docker environment. You'll get the following components out of the box with our docker-compose:
- Echo API (upstream)
Just a simple rack application that echoes back in a JSON whatever is gets in the request. You can control the response by passing the custom HTTP headers X-Echo-Status and X-Echo-Message (both optional). - Envoy proxy
Configured w/ the ext_authz http filter. - Authorino
The AuthN/AuthZ broker with this configuration preloaded. - OPA service
An actual Policy Decision Point (PDP) configured in the architecture. - Keycloak
To issue OIDC access tokens and to provide ad-hoc resource data for the authorization payload.
- Admin console: http://localhost:8080/auth/admin (admin/p)
- Preloaded realm: ostia
- Preloaded clients:
- demo: to which API consumers delegate access and therefore the one which access tokens are issued to
- authorino: used by Authorino to fetch additional user info with
client_credentials
grant type - pets-api: used by Authorino to fetch UMA-protected resource data following typical UMA flow
- Preloaded resources:
/pets
/pets/1
(owned by user jonh)/stats
- Realm roles:
- member (default to all users)
- admin
- Preloaded users:
- john/p (member)
- jane/p (admin)
Start by cloning the repo:
git clone [email protected]:3scale-labs/authorino-rb.git
cd authorino/examples
docker-compose up --build -d
John is a member user of the ostia
realm in Keycloak. He owns a resource hosted at /pets/1
and has no access to /stats
.
export ACCESS_TOKEN_JOHN=$(curl -k -d 'grant_type=password' -d 'client_id=demo' -d 'username=john' -d 'password=p' "http://localhost:8080/auth/realms/ostia/protocol/openid-connect/token" | jq -r '.access_token')
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JOHN" http://localhost:8000/pets -v # 200 OK
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JOHN" http://localhost:8000/pets/1 -v # 200 OK
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JOHN" http://localhost:8000/stats -v # 403 Forbidden
Jane is an admin user of the ostia
realm in Keycloak. She does not own any resource and has access to /stats
.
export ACCESS_TOKEN_JANE=$(curl -k -d 'grant_type=password' -d 'client_id=demo' -d 'username=jane' -d 'password=p' "http://localhost:8080/auth/realms/ostia/protocol/openid-connect/token" | jq -r '.access_token')
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JANE" http://localhost:8000/pets -v # 200 OK
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JANE" http://localhost:8000/pets/1 -v # 403 Forbidden
curl -H 'Host: echo-api:3000' -H "Authorization: Bearer $ACCESS_TOKEN_JANE" http://localhost:8000/stats -v # 200 OK
docker-compose down