Cognito Identity Pool のタスク/ルールベースマッピングで User Pool のグループに対応するロールの一時クレデンシャルを発行する

awsauth

Cognito Identity Pool は User Pool などの IdP で認証されたユーザーに一時的な AWS クレデンシャルを発行できる機能。

CDKでCognito UserPoolとClientを作成しトリガーやFederationを設定する - sambaiz-net

const identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', {
  identityPoolName: 'test-identity-pool',
  allowUnauthenticatedIdentities: false,
  cognitoIdentityProviders: [{
    clientId: userPoolClient.userPoolClientId,
    providerName: userPool.userPoolProviderName,
  }],
});

発行するクレデンシャルの IAM Role は、precedence が最小の group の cognito:preferred_role claim または cognito:roles claim + CustomRoleArn による Token ベースか、任意の claim に対してルールベースで設定する。

const defaultRole = new iam.Role(this, 'DefaultRole', {
  roleName: `default-role`,
  assumedBy: new iam.FederatedPrincipal(
    'cognito-identity.amazonaws.com',
    {
      'StringEquals': {
        'cognito-identity.amazonaws.com:aud': identityPool.ref,
      },
      'ForAnyValue:StringLike': {
        'cognito-identity.amazonaws.com:amr': 'authenticated',
      },
    },
    'sts:AssumeRoleWithWebIdentity'
  ),
});


new cognito.CfnUserPoolGroup(this, 'AdminGroup', {
  userPoolId: userPool.userPoolId,
  groupName: 'admin-users',
  description: 'Admin users',
  roleArn: defaultRole.roleArn, // cognito:roles, cognito:preferred_role (Token based role mapping)
  precedence: 0,
});

new cognito.CfnIdentityPoolRoleAttachment(this, 'RoleAttachment', {
  identityPoolId: identityPool.ref,
  roles: {
    authenticated: defaultRole.roleArn,
  },
  roleMappings: {
    'cognito': {
      identityProvider: `${userPool.userPoolProviderName}:${userPoolClient.userPoolClientId}`,
      type: 'Rules', // or Token
      ambiguousRoleResolution: 'AuthenticatedRole',
      rulesConfiguration: {
        rules: [
          {
            claim: 'cognito:groups',
            matchType: 'Contains',
            value: 'admin-users',
            roleArn: adminRole.roleArn,
          },
          {
            claim: 'cognito:groups',
            matchType: 'Contains',
            value: 'normal-users',
            roleArn: normalRole.roleArn,
          },
        ],
      },
    },
  },
});

次のようにしてクレデンシャルを取得することができる。

import { CognitoIdentityClient, GetIdCommand, GetCredentialsForIdentityCommand } from '@aws-sdk/client-cognito-identity';

const client = new CognitoIdentityClient({ region: 'ap-northeast-1' });
const providerName = `cognito-idp.ap-northeast-1.amazonaws.com/${userPoolId}`;

const getIdResponse = await client.send(new GetIdCommand({
  IdentityPoolId: identityPoolId,
  Logins: { [providerName]: idToken },
}));

const credentialsResponse = await client.send(new GetCredentialsForIdentityCommand({
  IdentityId: getIdResponse.IdentityId,
  Logins: { [providerName]: idToken },
}));

const credentials = {
  accessKeyId: credentialsResponse.Credentials.AccessKeyId,
  secretAccessKey: credentialsResponse.Credentials.SecretKey,
  sessionToken: credentialsResponse.Credentials.SessionToken,
};