aws / aws-appsync-community

The AWS AppSync community
https://aws.amazon.com/appsync
Apache License 2.0
507 stars 32 forks source link

Cross account IAM auth - AppSync resource policy #157

Open paulsson opened 3 years ago

paulsson commented 3 years ago

AppSync is an amazing service for running GraphQL APIs. Just as with REST APIs when using API Gateway we should be able to call the GraphQL API from other systems which reside in other AWS accounts. I do not see a way to setup the cross-account bi-directional trust like you can do so easily with API Gateway via a "Resource Policy". Does AppSync already support cross-account IAM auth somehow that I can't find in the AppSync Console or documentation anywhere? If not, I think AppSync is missing a HUGE use case of allowing "systems" (lambda, ECS, EC2, anything that uses an IAM role) to also be a AppSync client. I can make this work if the calling client (lambda role) is from the same AWS account as where the AppSync API is running, but there isn't anyway to support this from a different AWS account that I see. I could see a B2B case where a business may want to expose their AppSync API to a partner who also runs in AWS or if a company just has multiple AWS accounts which is very common. I'd rather not "assume" an IAM role from the AWS account where AppSync is running... that is just a PITA. @awsed any thoughts on this? I'd be happy to discuss.

Thanks, Erik

KoldBrewEd commented 3 years ago

Hi Erik,

Unfortunately indeed AppSync does not support IAM resource-based policies yet. However while I cannot share ETAs this in our backlog, stay tuned!

Ed

paulsson commented 3 years ago

Thanks for the quick update @awsed ! Any chance AppSync custom Route53 domains which will work with IAM auth is on the backlog / roadmap as well? There is a lot of people asking for it: https://github.com/aws/aws-appsync-community/issues/5

Thanks, Erik

jdonboch commented 3 years ago

Definitely need this feature!

mikel67 commented 3 years ago

Hi Erik,

Unfortunately indeed AppSync does not support IAM resource-based policies yet. However while I cannot share ETAs this in our backlog, stay tuned!

Ed

Any updates on the progress or plans for resource-based access.

Of specific interest is having an AppSync API use a Cognito User Pool in another account. This would allow us to separate domain services into different accounts but to access these with authentication via a common user pool. Currently we are forced to deploy all domain services in the same account with the user pool.

zhenyakovalyov commented 3 years ago

Hi @awsed, we are also looking for this functionality with roughly the same case.

kyalha commented 2 years ago

@paulsson Using a resource policy isn't possible but you can use a Role. I made it working this way. Now I can call my appsync api "cross-accountly".

robinclark commented 1 year ago

@kyalha Do you mind sharing how you got this to work? I haven't been able to get my setup to work.

What I've tried

I have two AppSync services in two accounts, A and B. AppSync A has an HTTP data source to make requests to AppSync B. I created a role in account B that permits all API actions on AppSync B.

Approach 1: Pass account B role ARN to account A's HTTP data source

// permissions

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "appsync:GraphQL",
            "Resource": "arn:aws:appsync:us-west-2:{account-B-number}:apis/{api-id}/*",
            "Effect": "Allow"
        }
    ]
}

// trust relationship

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com",
                "AWS": "arn:aws:iam::{account-A-number}:root"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Attempting a request from A->B resulted in this error message

Cross-account pass role is not allowed. (Service: AWSAppSync; Status Code: 403; Error Code: AccessDeniedException...)

Seems that's not possible according to this article.

You cannot use the PassRole permission to pass a cross-account role.

Approach 2: Create a role in account A, with permission to assume the role in account B, and pass that role ARN to account A's HTTP data source

// permissions

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::{account-B-number}:role/AuditScheduling-AppSyncAP-InvokeAppSyncAPIRole",
            "Effect": "Allow"
        },
        {
            "Action": "appsync:GraphQL",
            "Resource": "arn:aws:appsync:us-west-2:{account-B-number}:apis/{account-B-id}/*",
            "Effect": "Allow"
        }
    ]
}

// trust relationship

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com",
                "AWS": "arn:aws:iam::{account-A-number}:root"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

The approach was inspired from this post

I still get an unauthorized error when making an HTTP request from A to B, so I'm not sure that AppSync A is switching to the role in account B.

Note

According to this AppSync doc, you can limit the trust policy on a data source so that only a certain account can assume its role. This seems to suggest that you could create a data source in account B that AppSync in account A could invoke. I don't see a way, however, to create a data source in account A, with the ARN from the data source in account B. Also, this approach seems unscalable since for every service I want to integrate, I'd need to add a data source in that service's AWS account.

Possible workaround

Use a lambda resolver instead of the AppSync direct access, and have the lambda assume the cross-account role and sigv4 sign the request. That would incur added cost for the lambda though, I'd have to keep it warm, and do the sigv4 signing. See Choosing between direct data source access and proxying via a Lambda data source

khellan commented 1 year ago

Two years later and this is still not possible. We want to isolate the external API used by our partners in a separate account and the only way to do this is by assuming a role? If IAM is deprecated in AWS; please let us know what we should use instead for other services as well. Assuming a role in a different account in order to call an API is not the way.

adriantaut commented 1 day ago

Also looking for resource based policies as proved to be very useful in API Gateways