Gerharddc
Gerharddc

Reputation: 4089

Access Congito authorized AppSync API from a Lambda function

I want to invoke mutations on my AppSync API from Lambda functions in response to external events. Now I have been able to do this if I set AppSync to use IAM authorization and then provide access in the role of my Lambda function. The problem is that I need to use Cognito authorization because I need access to Cognito usernames in many of my resolver templates and I do not know of any way to do this when using IAM authorization.

I would thus like to know if there is any way I can authorise a Lambda function using Cognito User Pools to call my AppSync endpoint. Obviously I can create a dummy user in my pool and simply log in with it in the Lambda but Cognito User Pool logins are a very slow process and this method just sounds wrong anyway. The mutations I want to call from Lambdas don't need any Cognito info anyway.

What would also solve my problem is if I had a way to access the Cognito username in resolver templates when using IAM authorization.

Upvotes: 3

Views: 1328

Answers (2)

Jeff Bailey
Jeff Bailey

Reputation: 5775

With user pools as your authentication mechanism, there is no way to get tokens to authorize with AWS AppSync without signing in, at some point. With that said, you could mitigate the overhead of that a bit. Ultimately, it boils down to what you suggested in your question, using a 'fake user'. It's not an uncommon solution, and involves having some admin level user, the credentials for whom would only be accessed from this Lambda.

First of all, I would recommend you not use the traditional SRP login, for latency reasons. One alternative would be to use AdminInitiateAuth/ADMIN_NO_SRP_AUTH, to offload the overhead of SRP calculations from your Lambda to the Cognito back end, with ADMIN_NO_SRP_AUTH turned on in your pool. I saw from your other question (Authenticate AppSync request with adminInitiateAuth) that you were thinking of doing this, however it is important to point out this is simply a different API used to sign a user in. You can read more about it here: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-server-side-authentication-flow

An additional alternative could be a custom authentication flow. The same link above has more details on how to do this, but in short, you could set up a quicker flow that fits whatever specific needs your add has.

To improve overhead a bit more, you could then keep those tokens cached, to some degree. That could just mean keeping it in memory in the Lambda and checking their validity/expiry before using them, or even attaching a remote caching mechanism.

Upvotes: 2

Pedro Arantes
Pedro Arantes

Reputation: 5379

@Gerharddc, what if do you try to add policies that allow unauthenticated access to your Cognito Identity Pool?

I have this piece of code that defines authenticated and unauthenticated access to my Identity Pool (you can check the full code here in my personal project).

IdentityPoolUnauthorizedIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool
              ForAnyValue:StringLike:
                cognito-identity.amazonaws.com:amr: unauthenticated
      Policies:
        - PolicyName: CognitoUserSignInUnauthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - mobileanalytics:PutEvents
                  - mobiletargeting:PutEvents
                  - cognito-sync:*
                  - cognito-identity:*
                Resource: '*'

  IdentityPoolAuthorizedIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool
              ForAnyValue:StringLike:
                cognito-identity.amazonaws.com:amr: authenticated
      Policies:
        - PolicyName: CognitoUserSignInAuthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - mobileanalytics:PutEvents
                  - mobiletargeting:PutEvents
                  - cognito-sync:*
                  - cognito-identity:*
                Resource: '*'

  # Assigns the roles to the Identity Pool
  CognitoIdentityPoolRoleAttachment:
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties:
      IdentityPoolId: !Ref CognitoIdentityPool
      Roles:
        unauthenticated: !GetAtt IdentityPoolUnauthorizedIAMRole.Arn
        authenticated: !GetAtt IdentityPoolAuthorizedIAMRole.Arn

When I declare my AWS AppSync template, I add this template that permits users to access my AppSync endpoint when signed in:

AppSyncIAMPolicy:
    Type: AWS::IAM::Policy
    Description: Allow user consume AppSync when signed in
    DependsOn: AppSyncGraphQLApi
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - appsync:GraphQL
            Resource:
              - !Join ['/', [!GetAtt AppSyncGraphQLApi.Arn, '*']]
      PolicyName: !Sub ${StackName}-appsync-iam-policy
      Roles:
        - !Sub ${IdentityPoolAuthorizedIAMRoleRef}

My point is: you can attach a policy that allows users not signed (unauthenticated) access AppSync. Instead - !Sub ${IdentityPoolAuthorizedIAMRoleRef} you can in the template above, you can try - !Sub ${IdentityPoolUnauthorizedIAMRoleRef}.

Of course, you can specify which endpoints you allow unauthenticated access, for example:

AppSyncIAMPolicy:
    Type: AWS::IAM::Policy
    Description: Allow user consume AppSync when NOT signed in
    DependsOn: AppSyncGraphQLApi
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - appsync:GraphQL
            Resource:
              - arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-1>
              - arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-2>
      PolicyName: !Sub ${StackName}-appsync-iam-policy-unauthenticated
      Roles:
        - !Sub ${IdentityPoolUnauthorizedIAMRoleRef}

Upvotes: 0

Related Questions