1
votes

Short version

Logged in as a Facebook user, I use my oAuth token to assume an IAM role on AWS. It returns what looks to be valid credentials, e.g. there is an AccessKeyId, SecretAccessKey that are similar length to our master keys.

When I try to use these credentials to access a DynamoDB table, I get one of two exceptions:

  1. "The remote server returned an error: (400) Bad Request."; or
  2. "The security token included in the request is invalid.".

I'm using the AWS C# SDK version 1.5.25.0

Long version

As I said above, I'm trying to access a DynamoDB table on AWS using credentials supplied by AmazonSecurityTokenServiceClient authorized by Facebook Identity as described in this AWS guide.

The policy for the IAM role that I've created is:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "dynamodb:BatchGetItem",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem"
      ],
      "Sid": "Stmt1372350145000",
      "Resource": [
        "*"
      ],
      "Effect": "Allow"
    }
  ]
}

How I get the credentials:

  1. The user logs in with Facebook using oAuth.
  2. Using the access token, I assume the IAM role using a AmazonSecurityTokenServiceClient.AssumeRoleWithWebIdentity with a request.
  3. This returns what looks like to be valid credentials, e.g. a AccessKeyId, SecretAccessKey that are similar length to our master keys.

    using (var tokenServiceClient = new AmazonSecurityTokenServiceClient(RegionEndpoint.USEast1))
    {
        var request = new AssumeRoleWithWebIdentityRequest
        {
            DurationSeconds = (int)TimeSpan.FromHours(1).TotalSeconds,
            ProviderId = "graph.facebook.com",
            RoleArn = "arn:aws:iam::193557284355:role/Facebook-OAuth",
            RoleSessionName = result.id,
            WebIdentityToken = FBClient.AccessToken
        };
    
        var response = tokenServiceClient.AssumeRoleWithWebIdentity(request);
    
        AWSAssumedRoleUser = response.AssumeRoleWithWebIdentityResult.AssumedRoleUser;
        AWSCredentials = response.AssumeRoleWithWebIdentityResult.Credentials;
    }
    

How I use these credentials:

Using the returned credentials, I then try to access a AWS DynamoDB resource.

using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, AWSCredentials.SessionToken, RegionEndpoint.USEast1))
{
    var context = new DynamoDBContext(client);
    var data = context.Scan<SomeData>();    
}

This returns "The remote server returned an error: (400) Bad Request." when trying to Scan the table.

This is where the variation in the exception message is; if I omit the AWSCredentials.SessionToken from the above AmazonDynamoDBClient

using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, RegionEndpoint.USEast1))
{
    var context = new DynamoDBContext(client);
    var data = context.Scan<SomeData>();
}

This returns "The security token included in the request is invalid." when trying to Scan the table.

Question

At this point I cannot tell what is wrong, are the credentials invalid or that I'm not passing everything through that is needed to AWS.

Can anyone offer any insight to what is wrong or how I could debug this further?

1

1 Answers

2
votes

I cross-posted my question to the AWS forums and received an answer from an Amazon engineer.

https://forums.aws.amazon.com/message.jspa?messageID=465057


DynamoDBContext object invokes DescribeTable on the target table (and caches this data, so for optimal performance you would want to keep the context object around for as long as possible, so this call is only done once per target table). Modify your policy as follows:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "dynamodb:BatchGetItem",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:DescribeTable"        
      ],
      "Sid": "Stmt1372350145000",
      "Resource": [
        "*"
      ],
      "Effect": "Allow"
    }
  ]
}