AWS Developer Tools Blog

Web Identity Federation using the AWS SDK for .NET

Today’s post is about web identity federation. AWS Security Token Service (STS) has introduced this new feature, which allows customers to give constrained, time-limited access of their AWS resources to users who identify themselves via popular third-party identity providers (IdPs). AWS currently supports Amazon, Facebook, and Google as IdPs whose tokens can be used to gain access to AWS resources. This feature enables scenarios where app developers can give their customers access to AWS resources under their own (developers’) accounts in a controlled fashion using the customer’s existing account with any of the IdPs. By taking this approach, developers don’t need to distribute their AWS credentials in their applications and do account management for their customers. If you are interested in using this feature in your Windows Phone or Windows Store apps, check out the Developer Preview of the next version of the AWS SDK for .NET. The Developer Preview adds support for .NET Framework 4.5 and the Windows Phone and WinRT platforms.

We’ll now look at the steps required for you to use web identity federation and a few C# code snippets that will show you how to get temporary access tokens and access AWS resources after authenticating with an IdP. We are using Facebook as the IdP in the sample below. For details on using other IdPs, check this link.

Setting up an IAM role

We start off by creating an IAM role (this is a one-time activity.) This is the role that your users will assume when they successfully authenticate through an IdP. When you create this role, you need to specify two policies: the trust policy, which specifies who can assume the role (the trusted entity, or principal), and the access policy, which describes privileges associated with this role. Below is an example of a trust policy using Facebook as the IdP.

{
  "Version":"2012-10-17",
  "Id":"RoleForFacebook",
  "Statement":[{
      "Principal":{"Federated":"graph.facebook.com"},
      "Effect":"Allow",
      "Action":"sts:AssumeRoleWithWebIdentity",
      "Condition": {
          "StringEquals":
              {“graph.facebook.com:app_id":"MY_APP_ID"}
       }
   }]
}

You’ll need to replace the string MY_APP_ID with your Facebook app ID. This policy allows the users authenticated through Facebook IdP to use the web identity federation API (AssumeRoleWithWebIdentity operation), which grants the users temporary AWS credentials. We also have a condition in the policy that the Facebook app ID should match the specified one. This policy also makes use of policy variables, which are discussed in more detail here.

When creating your IAM role via the AWS Management Console, the Role Creation wizard will walk you through the process of creating the trust policy, but you will need to supply the access policy by hand. Below is the access policy that specifies the privileges associated with this role. In this sample, we will provide access to S3 operations on a bucket designated for the Facebook app. You’ll need to replace MY_APPS_BUCKET_NAME with the bucket name for your app.

{
 "Version":"2012-10-17",
 "Statement":[{
   "Effect":"Allow",
   "Action":["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
   "Resource": "arn:aws:s3:::MY_APPS_BUCKET_NAME/${graph.facebook.com:id}/*"
  },
  {
   "Effect":"Allow",
   "Action":"s3:ListBucket",
   "Resource":["arn:aws:s3:::MY_APPS_BUCKET_NAME"],
   "Condition":
     {"StringLike":
       {"s3:prefix":"${graph.facebook.com:id}/"}
     }
  }
 ]
}

The first statement in this policy allows each user of the app to Get, Put, or Delete objects in the specified S3 bucket with a prefix containing their Facebook user ID. This has the effect of creating “folders” for each user under which their objects will reside. The second statement allows users to retrieve only their objects’ contents by enforcing the prefix condition on the specified bucket.

Connecting with the identity provider

Now that the IAM role is in place you can call the STS AssumeRoleWithWebIdentity API, specifying the ARN of the IAM role that you created and a token provided by the IdP. In this example using Facebook, the token would be the access token that Facebook login provides in response to an authentication request (details on how we get the Facebook access token are not covered in this post, this link is a good starting point to understand the Facebook login process). Here is the C# snippet for calling AssumeRoleWithWebIdentity. Notice that we pass in an AnonymousAWSCredentials object for the credentials parameter when constructing the STS client, as we do not need to have AWS credentials to make this call.

var stsClient = new AmazonSecurityTokenServiceClient(new AnonymousAWSCredentials());

// Assume the role using the token provided by Facebook.
var assumeRoleResult = stsClient.AssumeRoleWithWebIdentity(new AssumeRoleWithWebIdentityRequest
{
    WebIdentityToken = "FACEBOOK_ACCESS_TOKEN",
    ProviderId = "graph.facebook.com",
    RoleArn = "ROLE_ARN",
    RoleSessionName = "MySession",
    DurationSeconds = 3600
}).AssumeRoleWithWebIdentityResult;

Here are the parameters we pass to the API.

  • WebIdentityToken – the token received from the IdP after a user authenticates with it.
  • ProviderId – the name of the IdP. The supported values are graph.facebook.com, www.amazon.com, and googleapis.com.
  • Role ARN – the Amazon Resource Name of the role the user will assume. The ARN is of the format arn:aws:iam::123456789012:role/RoleForFacebook.
  • RoleSessionName – the name to give to this specific session. This name is used to identify the session.
  • DurationSeconds – the duration for which the security token that is returned will be valid, in seconds. The default value is 1 hour (3600 seconds).

Accessing AWS resources

The AssumeRoleWithWebIdentity API returns a session token that your application can use to access any resource mapped to the role. This is done by constructing a SessionAWSCredentials object and using it for subsequent calls to access resources and perform actions permitted by the assumed role. The below sample code accesses the objects in the app’s S3 bucket and performs operations on them. Remember that in the access policy you provided when creating the role, the user was restricted to access only S3 objects that contained the Facebook username prefixed to the path. Here assumeRoleResult.SubjectFromWebIdentityToken is the Facebook provided user id of the customer and objectName is the name of the S3 object being created.

// Create an S3 client using session credentials returned by STS
var credentials = assumeRoleResult.Credentials;
SessionAWSCredentials sessionCreds = new SessionAWSCredentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.SessionToken);
var s3Client = new AmazonS3Client(sessionCreds, s3Config);

var key = string.Format("{0}/{1}", assumeRoleResult.SubjectFromWebIdentityToken, objectName);

// Put an object in the user's "folder".
s3Client.PutObject(new PutObjectRequest
{
    BucketName = "MY_APPS_BUCKET_NAME",
    Key = key,
    ContentBody = content
});

// List objects in the user's "folder".
var listObjectResponse = s3Client.ListObjects(new ListObjectsRequest
{
    BucketName = "MY_APPS_BUCKET_NAME",
    Prefix = assumeRoleResult.SubjectFromWebIdentityToken + "/"
});

// Get the object with the specified key.
var getObjectRespone = s3Client.GetObject(new GetObjectRequest
{
    BucketName = "MY_APPS_BUCKET_NAME",
    Key = key
});

Summary

In this post, we saw how web identity federation can be used to give access to AWS resources to customers who authenticate through one of the supported IdPs. We also walked through the steps and code snippets to use this feature.