3
votes

I can't see a good design for claims- or role-based authorization over an AWS PaaS (gateway/lambda) API. Right now, there seems to be a functionality blindspot regardless of how you combine the following:

  • gateway cognito user pool or custom authorizers
  • cognito identity pools used for web and user pool identity federation
  • IAM roles for gateway execution authorization

Specifically, the blindspot seems to be associating cognito identities with roles (more varied than keys and suffixes in dynamo and s3) based on user attributes in a way that:

  • doesn't require a custom endpoint in your API to vend IAM temp creds (and consequently using something other than the supplied and/or generated SDKs)
  • doesn't require authorization logic in every lambda function
  • doesn't require persisting the above mapping in dynamo, cognito sync, etc
  • doesn't layer or sequence a separate flow for authorization (e.g. separate token)
  • lets your users sign in using external idps

I assume the following is impossible or excessively hacky:

  • cognito user pools that overlap or moving users between pools to represent the configuration of their roles
  • directly getting cognito user pool attributes from congito identity pool identity tokens (GetOpenIdToken)
  • having a readily-modifiable client pick its own privileges (e.g. choose an IAM role)
  • running every request as dry-run in a custom authorizer or otherwise shadow-implementing IAM
  • securing actually role-specific IAM roles with some kind of shared secret, etc.

Here are some examples and their shortcomings:

  1. A user logs in with user pool credentials and attempts to execute a gateway api method.
    1. A cognito authorizer over gateway api methods would let me say autheticated-therefore-authorized and map attributes/claims into the integration request, still leaving it to the lambda function to implement actual authorization logic.
    2. A custom authorizer won't automatically validate and parse a user pool token, but I could still do so and conditionally construct a role.
  2. A user logs in with google+ credentials, having a user pool identity as well, and attempts to execute a gateway api method.
    1. A cognito authorizer is useless.
    2. A custom authorizer won't automatically validate and parse the google+ token, but I could still do so and conditionally construct a role. Only now I'd need to map this to a user pool identity manually. Cognito adds no value at all here -- just an awkward document database as a service.
  3. A user logs in with google+ credentials, having a user pool identity as well, then gets an identity pool token (GetOpenIdToken) and attempts to execute a gateway api method.
    1. A cognito authorizer is useless.
    2. A custom authorizer won't automatically validate and parse the cognito identity token, but I could still do so and conditionally construct a role. I still need to do manual mapping because I won't get the user pool attributes with this intermediate token.
  4. A user logs in with google+ credentials, having a user pool identity as well, then gets temp creds (GetCredentialsForIdentity) and attempts to execute a gateway api method.
    1. The default authorizer is useless. You just get authenticated-therefore-authorized.
    2. A cognito authorizer is useless.
    3. A custom authorizer is useless.
1

1 Answers

2
votes
  • The easiest solutions to most of these problems are in User Pools (i.e. using Lambda hooks in the auth flow to check privileges, attributes can be retrieved from the token an authentication generates...etc.), however your requirement that users can sign in with external providers is not currently supported.
  • From that, you can potentially use Cognito federated identities with user pools and external providers, but that brings up some awkwardness. Building in the privilege authentication into the user pools lambda hooks when multiple providers are available is awkward and forces the usage of user pools with other providers.
  • From that, I would say mapping privileges to identity id in some external storage is the way to go, using some external hook (Lambda?) with that id to assume a role and get credentials, but you mentioned you wouldn't want to do that.

I would agree that what you're aiming for is not absolutely possible as is. My recommendation might be to get in touch with an SA and see if they can help you design a complex solution that fulfills your requirements.