AWS Developer Tools Blog

Creating Access Policies in Code

AWS uses access policies to restrict access to resources. These policies are JSON documents that have statements, actions, resources, and conditions. You could use a JSON parser to create these documents in code, but a better way would be to use the AWS SDK for .NET Policy object found in the Amazon.Auth.AccessControlPolicy namespace. This gives you type safety and is much more readable than writing text to a JSON parser. For example, imagine you are building a system where desktop clients upload user data directly to Amazon S3 instead of uploading to a web server that would do the upload to S3. You don’t want to bundle the credentials to get to S3, so the desktop clients need to get their credentials from a web server. You want the clients to be able to do GET and PUT requests in S3 under their username in a specific bucket.

The following code creates the policy object. For this case, you need only one statement. It has a resource of bucket + username and the GET and PUT actions. As an added security measure, let’s add a condition that locks the GET and PUT request to the IP address of the desktop client.

public Policy GeneratePolicy(string bucket, string username, string ipAddress)
{
    var statement = new Statement(Statement.StatementEffect.Allow);

    // Allow access to the sub folder represented by the username in the bucket
    statement.Resources.Add(ResourceFactory.NewS3ObjectResource(bucket, username + "/*"));

    // Allow Get and Put object requests.
    statement.Actions = new List() 
        { S3ActionIdentifiers.GetObject,  S3ActionIdentifiers.PutObject };

    // Lock the requests coming from the client machine.
    statement.Conditions.Add(ConditionFactory.NewIpAddressCondition(ipAddress));

    var policy = new Policy();
    policy.Statements.Add(statement);

    return policy;
}

Once you have the policy, you can create a federated user, like this:

public Credentials GetFederatedCredentials(Policy policy, string username)
{
    var request = new GetFederationTokenRequest()
    {
        Name = username,
        Policy = policy.ToJson() 
    };

    var stsClient = new AmazonSecurityTokenServiceClient();

    var response = stsClient.GetFederationToken(request);
    return response.GetFederationTokenResult.Credentials;
}

The credentials object contains a temporary access key, a secret key, and a session token that can be sent back to the desktop client. The desktop client can then construct an S3 client, like this:

string accessKeyId, secretAccessKey, sessionToken;
GetCredentialsFromWebServer(out accessKeyId, out secretAccessKey, out sessionToken);

var sessionCredentials = new SessionAWSCredentials(accessKeyId, secretAccessKey, sessionToken);
AmazonS3 s3Client = new AmazonS3Client(sessionCredentials, RegionEndpoint.USWest2);

public void GetCredentialsFromWebServer(out string accessKeyId, out string secretAccessKey, out string sessionToken)
{
    ... Make web request to get temporary restricted credentials. ...
}

Now the desktop client can upload and download data to S3 without the ability to access other user’s data.