Protect an S3 Bucket using the Cognito username claim

221 Views Asked by At

I'm using the cdk to create a User Pool, Identity Pool and S3 bucket. I am successfully able to protect the S3 Bucket using the Identity Pool sub. What I would like to do instead is use the username of the cognito user.

I know this can be done because of this post from AWS allowing S3 Buckets to be accessed with custom attributes.

Here's how I'm currently going about it:

import * as cognito from "aws-cdk-lib/aws-cognito";
import * as cdk from "aws-cdk-lib";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { Construct } from "constructs";
import {
  IdentityPool,
  UserPoolAuthenticationProvider
} from "@aws-cdk/aws-cognito-identitypool-alpha";
import {
  Effect,
  Policy,
  PolicyDocument,
  PolicyStatement
} from "aws-cdk-lib/aws-iam";

export class CognitoResources extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const bucket = new Bucket(this, "MyBucket");

    const userPool = new cognito.UserPool(this, "UserPool");

    const client = new cognito.UserPoolClient(this, `UserPoolClient`, {
      userPool
    });

    const identityPool = new IdentityPool(this, `IdentityPool`, {
      authenticationProviders: {
        userPools: [
          new UserPoolAuthenticationProvider({
            userPool,
            userPoolClient: client
          })
        ]
      }
    });

    const bucketCognitoArn =
      `${bucket.bucketArn}/user/` + "${aws:PrincipalTag/username}/*";

    identityPool.authenticatedRole.attachInlinePolicy(
      new Policy(this, "S3IdenityPoolAccessPolicy", {
        document: new PolicyDocument({
          statements: [
            new PolicyStatement({
              actions: ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
              resources: [bucketCognitoArn],
              effect: Effect.ALLOW
            }),
            new PolicyStatement({
              actions: ["s3:GetObject"],
              resources: [`${bucket.bucketArn}/user/*`],
              effect: Effect.ALLOW
            })
          ]
        })
      })
    );
  }
}

If I replace aws:PrincipalTag/username with cognito-identity.amazonaws.com:sub, then this works fine. I'm looking for help on how to use a username as the access attribute.

From what I call tell I might need to edit the trust policy on the assume role policy and add sts:TagSession, as well as perform attribute mapping for the username attribute from the user pool to the identity pool. The docs on this are mostly about mapping attributes from social log ins, and none are very helpful on how to do this with cdk.

Any help is appreciated! I would like to do this all in cdk without the console if possible :)

1

There are 1 best solutions below

0
Kieron McKenna On

After many hours of trial and error I had to manually add sts:TagSession to the assume role policy of the authenticated role for the identity pool, as well as make custom attribute mapping from "cognito:username" to "u".

"u" being a Tag key for principal that is anything other than "username", there must be something conflicting inside cognito that would not allow the username tag to work.

Hopefully this saves someone some time.