Skip to content

Latest commit

 

History

History
164 lines (104 loc) · 9.82 KB

security.md

File metadata and controls

164 lines (104 loc) · 9.82 KB

Security

Concepts

Goals

  • Only Resource Providers can submit usage records.
    • Resource Providers can submit usage records only for their resources.
  • In case of processing errors, only an authorized user can reprocess usage records that are not yet processed.
  • Only authorized users can view usage reports.
    • Authorized users can view only their usage reports.

Design Constraints

  • Follow Cloud Foundry user authentication and authorization model.
  • Do not locally store user credentials and their roles.
  • Do not ask for user credentials to do the authorization.

HTTPS

Abacus uses HTTPS as a way to provide secure communication between:

  • Resource Providers and Abacus, and
  • internally between its pipeline steps/components

OAuth

Abacus uses OAuth to authorize:

  • Resource Providers usage submission to the pipeline
  • Users that want to view usage reports
  • Internal pipeline processing steps

OAuth uses access tokens. Abacus works with two types of access tokens: resource and system tokens.

Resource tokens

A Resource Provider is expected to present an OAuth token with the usage it submits for a (service or runtime) resource.

The OAuth token should include:

  • a user id uniquely identifying that Resource Provider
  • an OAuth scope named like abacus.usage.<resource_id>.write

A user that wants to get a report for a resource should present a token that has scope named abacus.usage.<resource_id>.read.

For example the linux-container resource provider should have scope abacus.usage.linux-container.write to submit usage. To get a report an user should present token with the abacus.usage.linux-container.read scope to the Abacus reporting component.

Additionally the resource usage document must contain resource_id, as specified in the API doc.

System token

After the submission Abacus 'takes custody' of the submitted data for processing. Abacus pipeline uses its own "system" token to authenticate and authorize the pipeline steps.

The system token has scopes abacus.usage.read and abacus.usage.write.

The Resource Providers can:

  • write data in the pipeline via the event collector (providing token with abacus.usage.<resource_id>.write scope)
  • read data from the pipeline via the reporting (token with abacus.usage.<resource_id>.read)

This system token is used to protect the pipeline from unauthorized (erroneous or even malicious) requests, made directly steps of the pipeline, other than the collector and reporting.

In order to read Abacus's health and hystrix stream, basic authentication is required. Abacus will use the provided basic authentication to obtain a bearer token and validates if the user has the abacus.system.read permission.

Token issuer

Abacus can work with Cloud Foundry's UAA or other token issuers, complying with JWT (https://tools.ietf.org/html/rfc7519) and JWS (https://tools.ietf.org/html/rfc7515) specifications.

The JWT specification (https://tools.ietf.org/html/rfc7519#page-16) only requires HMAC SHA-256 algorithm to be implemented to sign the message (or token), the other algorithms are either recommended or optional. And the JWS specification (https://tools.ietf.org/html/rfc7515#section-10.5) assumes shared key is used - same key to sign and validate the signature.

Token issuer can support both symmetric & asymmetric cryptographic algorithms for token signature and verification. UAA supports both.

Symmetric encryption is usually used when all parties are trusted (and can therefore be trusted with the key). In environments where not all parties are trusted, asymmetric encryption should be used.

Abacus requires a specific API to communicate with the Token issuer. This API is implemented in the example Authorization Server distributed with Abacus.

Token validation

The access tokens that are passed in the header serve as both a proof of authentication and authorization (via the scopes).

The validation of the request includes checks for:

  • presence of the bearer token
  • issuer, signature, expiry, scope

UAA exposes an endpoint called check_token, but it's use increases the traffic to UAA, which makes its use in loaded environments undesired.

On the other side the bearer token generated by UAA is a self validating JWT token. Therefore to reduce the load on UAA and increase the processing speed of the pipeline, Abacus validates the token using jsonwebtoken library, with configurable algorithm and secret. The secret can be a password string or a public key in case of asymmetric encryption.

Configuration

Abacus

To run Abacus in secure mode (HTTPS + OAuth tokens) you should modify Abacus application's manifest.yml files.

The set of properties that has to be changed contains:

  • SECURED - true / false - Use true to enable the security checks
  • AUTHSERVER - Authorization Server URL used to get access token endpoint in the format of https://hostname:port or just https://hostname.
  • CLIENT_ID - Client identifier registered with the specified authorization server.
  • CLIENT_SECRET - Client secret used to authenticate the client identifier with the authorization server.
  • JWTKEY - Key used to sign the JWT-JWS
  • JWTALGO - Cryptographic algorithm used to sign and secure JWT-JWS

You can use CF UAA or an Abacus authorization server as a OAuth token provider. We provide a sample implementation of such server - the Abacus authorization plugin.

Abacus authorization server

Use the following configuration:

  SECURED: true
  AUTH_SERVER: abacus-authserver-plugin
  CLIENT_ID: abacus
  CLIENT_SECRET: secret
  JWTKEY: encode
  JWTALGO: HS256

Note: The Authorization Server is an example implementation, defining the API Abacus uses. You should use it only for testing/development as it is not intended for productive usage.

CF UAA

Check your UAA configuration or CF deploy manifest on how the JSON Web Token (JWT) is signed. Search for:

  • JWT algorithm
  • public key (or secret)

Abacus configuration snippet for UAA should look like this:

    SECURED: true
    AUTH_SERVER: https://api.<CF domain>:443
    CLIENT_ID: abacus
    CLIENT_SECRET: secret
    JWTKEY: |+
      -----BEGIN PUBLIC KEY-----
      ... <UAA public key> ...
      -----END PUBLIC KEY-----
    JWTALGO: RS256

Cloud Foundry

The Abacus pipeline consists of several micro-services that run as CF applications. The applications communicate using the externally accessible endpoints, thus no special security settings are needed by default.

To pull monitoring data from all micro-service instances we need to be able to access a specific instance address. Cloud Foundry hides the instances behind a router, so this is not easily achievable. Cloud Foundry's router provides a single hostname for all instances of the same application. For example it cannot provide access to the 4th instance of an application, and instead it loadbalances between all of them.

To solve the problem we can use two approaches:

  • Netflix's Eureka
  • Cloud Foundry routing

Netflix's Eureka is a service discovery. All Abacus applications are registered in Eureka with their IP and port. This plays nice with the rest of Netflix products, such as Turbine, that contacts Eureka to get a list of addresses and use them to aggregate metrics streams. The needed configuration is described in the monitorig doc.

To enable monitoring with Eureka and Turbine, an Abacus integrator needs to run Abacus applications into a special security group. This group shall allow direct (app-to-app) communication between Turbine and Abacus applications, so that Turbine can access each microservice instance and fetch data for the individual app instance state. This app-to-app communication is considered a security risk. For development and testing on BOSH-Lite you can use the all access security group. However in production this is an additional attack vector, since if an attacker gains access to the Abacus pipeline, it can easily reach to all other CF applications.

To work around the security and routing issues we can scale Abacus micro-services as applications instead of app instances. We can push a micro-service as a set of applications. For example app-0, app-1 and app-2 can form a micro-service app with 3 instances. Check the Scaling Abacus doc for more info. We can still use Eureka to know which application belongs to which micro-service and to get hold of the set of endpoints that form the miscro-service.

The Abacus pipeline has 2 services that are used as user/agent-facing endpoints. We want theese to be accessible to users without forcing them to manually load-balance though several URLs, or granting them access to Eureka and thus binding them to our internal service discovery mechanism. These are the abacus-usage-collector that receives the usage reports from Resource Providers and abacus-usage-reporting that serves as an endpoint that generates usage reports.

Both of these micro-services can scale via different applications. We need to provide a single URL for easy access to the Resource Providers and report consumers. To do this we should map each set of applications to a new Cloud Foundry route using cf map-route. We can use:

  • abacus-usage-reporting for all usage-reporting- apps
  • abacus-usage-collector for all usage-collecotr- apps

In this way the providers and reporting consumers have to keep track of just one URL. The Cloud Foundry router handles the load-balancing between the 2 sets of applications.