👻

CognitoでユーザごとにS3フォルダアクセス制御をする

2023/07/10に公開

検索するとすでに色々情報があるので、こちらでは2023/07/05時点のCDKの実装について紹介したいと思います。

UserプールはL2 Constructがすでに用意されていますが、IDプールはまだalpha版です。モジュールが安定したら aws-cognito ライブラリに入るようです。そうすると、ちょっとごちゃごちゃしているauthenticatedRoleあたりもスッキリできるのかなぁと期待しています。

ポイントは

  • S3 Bucketの CORS設定
  • IDプールのauthenticatedRoleにポリシーを設定する
    あたりでしょうか。
import { Duration, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
import * as cognito from 'aws-cdk-lib/aws-cognito';
import { Construct } from 'constructs';
import { IdentityPool, UserPoolAuthenticationProvider } from '@aws-cdk/aws-cognito-identitypool-alpha';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';
import { CfnOutput } from 'aws-cdk-lib';

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

    const bucket = new s3.Bucket(this, 'bucket0705', {
      cors: [{
        allowedHeaders: ['*'],
        allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.PUT, s3.HttpMethods.POST, s3.HttpMethods.DELETE, s3.HttpMethods.HEAD],
        allowedOrigins: ['*'],
        exposedHeaders: ["ETag"]
      }],
      encryption: s3.BucketEncryption.KMS_MANAGED,
      bucketKeyEnabled: true,
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: true
    })

    const userPool = new cognito.UserPool(this, 'userPool0705', {
      userPoolName: 'userPool0705',
      signInCaseSensitive: false,
      selfSignUpEnabled: true,
      userVerification: {
        emailSubject: 'Verify your email',
        emailBody: 'Please verify your email by clicking on the following link: {####}',
        emailStyle: cognito.VerificationEmailStyle.CODE,
        smsMessage: 'Your verification code is {####}'
      },
      signInAliases: { email: true },
      autoVerify: { email: true }, 
      keepOriginal: { email: true },
      mfa: cognito.Mfa.OFF, 
      passwordPolicy: {
        minLength: 8,
        requireLowercase: true,
        requireUppercase: true,
        requireDigits: true,
        requireSymbols: true,
        tempPasswordValidity: Duration.days(1)
      },
      standardAttributes: {
        email: { required: true },
      },
      email: cognito.UserPoolEmail.withCognito(),  
      removalPolicy: RemovalPolicy.DESTROY
    })
    const client = userPool.addClient('userPoolClient0705', {})
    
    const idPool = new IdentityPool(this, 'identityPool0705', {
      identityPoolName: 'identityPool0705',
      authenticationProviders: {
        userPools: [new UserPoolAuthenticationProvider({userPool})]
      },
      allowClassicFlow: true,
      allowUnauthenticatedIdentities: false,
    })

    const s3Statement = new iam.PolicyStatement({
      actions: [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      resources: [
        bucket.bucketArn + "/private/${cognito-identity.amazonaws.com:sub}/*"
      ],
      effect: iam.Effect.ALLOW
    })
    const cognitoStatement = new iam.PolicyStatement({
      actions: [
        "cognito-identity:GetCredentialsForIdentity"
      ],
      resources: [
        "*"
      ],
      effect: iam.Effect.ALLOW
    })

    const authenticatedPolicy = new iam.Policy(this, 'authenticatedPolicy0705', {
      policyName: 'authenticatedPolicy0705',
      statements: [cognitoStatement,s3Statement]
    })
    idPool.authenticatedRole.attachInlinePolicy(authenticatedPolicy)

    const userPoolId = userPool.userPoolId
    const identityPoolId = idPool.identityPoolId

    new CfnOutput(this, 'userPoolId', {value: userPoolId})
    new CfnOutput(this, 'identityPoolId', {value: identityPoolId})
    new CfnOutput(this, 's3Bucket', {value: bucket.bucketName})
  }
}

Roleを作って idPool.authenticatedRole に設定しようとしたらうまくいかず、まずIDプールを作って、そのあとでポリシーを追加する形になっています。

これらの記事を参考にさせていただきました。ありがとうございます。

https://qiita.com/shiba_it/items/179c992a7ce068920329

Discussion