Managing multiple environments (prod/staging/dev)

Throughout the development life-cycle of your platform and product applications, you’ll have multiple environments. Common ones include Production and Staging, although there can be many more. This article answers the question of how best to architect your Authress account to manage having these different environments.

Background

The optimal solution encourages having only a single Authress account. There are many reasons for this:

  • Single ID - every account gets a unique Authress account ID. Having multiple increases complexity in your configuration.
  • Custom Domain - For higher reliability, Authress supports running on your domain via DNS subdomain. Every account must have a different DNS. With multiple accounts, along with different Authress account IDs, the url for the API has to be different.
  • UX - Access and usage for Developers and Support Engineers in Authress is easier and simpler when there is only one account.
  • User Identities - One of your users that logs in through different Authress accounts will get different IDs, since there is only one user there needs only to be one userId. Multiple accounts creates multiple user IDs.
  • Role management - roles do not have to be copied between environments, it is set once and it works. With multiple environments, the roles have to remain synced to ensure that the production version of your platform can specify roles that actually exist. Define the roles in one place, is a frequent implementation of the DRY software design principle.

Having multiple Authress accounts is supported, but not recommended. Where possible the Authress development team wants to enable a single Authress account to work for your use case. If for some reason it won’t work, please let us know.

Resources to manage

With multiple environments integrating with and operating in the same Authress account the following aspects need to be explicitly considered:

Service clients

The Authress recommendation is to create separate service clients for every environment. This provides two benefits:

  • Allows better tracking and auditing of resources that are generated/requested/authorized for users and the service client.
  • Separate API keys enable secure separation of access to the Authress API between your environments.

Roles

Overall, the same roles that work in one environment, will work for all environments. This is because roles are a collection of permissions (See Permissions and Roles for more information on this.) Permissions are scoped usually to a type of resource, and are of the form resource-type:action such as documents:read. There is no environment included in the permission or role, so roles can be reused.

Resource hierarchies

If we place an environment identifier in the resource path, for instance prod:tenants/{tenantId}, then throughout your application your environment identifier must present. This is brittle. A more reliable solution is for every resource ID that is generated to be unique to the relevant environment. For instance tenants could be generated with a tst_ prefix in non production environments, although in general, simple uuids will almost guarantee that there are no conflicts and avoids this extra and unnecessary complexity. Some platforms prefix the type of resource as part of the guid. Adding an extra character for the environment can be a great pattern to understand what the type of resource is just by looking at the id string. doc_tst_0123 versus com_prd_a1 immediately tell us a document created in the test environment as compared to a comment created in the production environment.

These aren’t required, but we have found common solutions that make it easy to solve most problems and get up and running with even very complex platforms.

  • Avoiding putting the environment in your resource hierarchy, service:prod:resources/{rId} is a bad idea. However, putting the environment in the IDs themselves, should not cause a problem.
  • Guarantee the generation of globally unique IDs using UUIDs for resources.
  • Generate multiple service clients one for each environment.
  • Give the service clients Admin (*) to service:resources/* for each type of resource that the service will control.
  • Create and modify access records with predictable IDs. While you can create generic access records, coupling them to either a user, a group, or a resource makes it easy to understand why it exists when doing investigation later. It also enables programmatic modification by convention rather than needing to store the recordId after generation.

Common questions

If the staging and production service clients both have Admin (*) access to all the services’ resources, isn’t this a security concern?

Generally, no. The reason is that even though they both have Admin access, the resources they have access to are only the ones that the service itself owns. The only service that checks access to these resources is itself. Concretely:

  • The Staging version theoretically has Admin access to all the production resources.
  • This access is checked by the Authress API when the Staging version attempts to create or edit access records that contain the service’s resources
  • The Staging service doesn’t have access to the Production version’s database

So even though the Staging service will check the same permissions as the Production service version, it can’t and won’t return the production version of the resources because it doesn’t have them in the database.

To further avoid issues here, it is common to generate an access record with the id Tenant:{TenantID}:ResourceType:{ResourceID}. This will cause a 409 if the other version of the service attempts to create that access record even though it already exists.

Didn't find what you were looking for?

Or send us an email at support@authress.io