我有一个 CloudWatch Evidently 项目,我想用它来控制公共 Web UI 上的功能标志。由于我无法在客户端应用程序中嵌入持久的 AWS 凭证,因此我知道 Cognito 是推荐的工具,可以允许未经身份验证的方式访问 AWS 服务。
我已经使用此 CloudFormation 模板创建了 Cognito 身份池、IAM 角色以及两者之间的链接:
CognitoIdentityPool:
Type: AWS::Cognito::IdentityPool
Properties:
AllowClassicFlow: True
AllowUnauthenticatedIdentities: True
IdentityPoolName: my-identity-pool
UIIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Federated: cognito-identity.amazonaws.com
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool
ForAnyValue:StringLike:
cognito-identity.amazonaws.com:amr: unauthenticated
MaxSessionDuration: 3600
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- cognito-identity:GetCredentialsForIdentity
- evidently:ListFeatures
- evidently:EvaluateFeature
Resource: '*'
IdentityPoolRoleAttachment:
Type: AWS::Cognito::IdentityPoolRoleAttachment
Properties:
IdentityPoolId: !Ref CognitoIdentityPool
Roles:
unauthenticated: !GetAtt UIIAMRole.Arn
控制台 UI 显示按预期创建的所有内容:在身份池上启用了来宾访问,与创建的 IAM 角色关联,并且该角色具有包含正确的明显权限的策略。
但是当我尝试接收凭据时,它说该角色无权使用 Evidently 功能:
$ aws cognito-identity get-id --identity-pool us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{
"IdentityId": "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
$ aws cognito-identity get-credentials-for-identity --identity-id us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{
"IdentityId": "us-east-1:xxxxxxxxxxxxxxxxxxxxx",
"Credentials": {
"AccessKeyId": "xxxxxxxxxxxxxxxxxxxxx",
"SecretKey": "xxxxxxxxxxxxxxxxxxxxx",
"SessionToken": "xxxxxxxxxxxxxxxxxxxxx",
"Expiration": "2023-11-30T11:03:53-05:00"
}
}
$ export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxxx
$ export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxx
$ export AWS_SESSION_TOKEN=xxxxxxxxxxxxxxxxxxxxx
$ aws evidently list-features --project my-evidently-project
An error occurred (AccessDeniedException) when calling the ListFeatures operation: User: arn:aws:sts::xxxxxxxxxxxx:assumed-role/my-role-UIIAMRole-xxxxxxxxxx/CognitoIdentityCredentials is not authorized to perform: evidently:ListFeatures on resource: arn:aws:evidently:us-east-1:xxxxxxxxxxxx:project/my-evidently-project/feature/*
我还尝试使用 Node SDK 获取和使用凭据:
const evidentlyClient = new EvidentlyClient({
region: 'us-east-1',
credentials: fromCognitoIdentityPool({
identityPoolId: 'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
clientConfig: { region: 'us-east-1' }
})
})
const featureResp = await evidentlyClient.send(
new ListFeaturesCommand({
project: 'arc-editorial-search-api'
})
)
也因同样的错误而失败。
谁能告诉我我做错了什么?
我认为问题中的方法是使用增强流程,根据本文档,该流程的权利有限。以下命令有效,我认为这对应于基本流程:
$ aws cognito-identity get-id --identity-pool us-east-1:xxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx
{
"IdentityId": "us-east-1:xxxxxxxxx"
}
$ aws cognito-identity get-open-id-token --identity-id us-east-1:xxxxxxxxx
{
"IdentityId": "us-east-1:xxxxxxxxx",
"Token": "xxx..."
}
$ aws sts assume-role-with-web-identity --role-arn arn:aws:iam::xxxxxxxxxxxx:role/my-iam-role --role-session-name test --web-identity-token xxx...
{
"Credentials": {
"AccessKeyId": "xxxxxxxxxxxxxxx",
"SecretAccessKey": "xxxxxxxxxxxxxxx",
"SessionToken": "xxxxxxxxxxxxxxx...",
"Expiration": "2023-12-01T15:56:05+00:00"
},
"SubjectFromWebIdentityToken": "us-east-1:xxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AssumedRoleUser": {
"AssumedRoleId": "xxxxxxxxxxxxxxxx:test",
"Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/my-iam-role/test"
},
"Provider": "cognito-identity.amazonaws.com",
"Audience": "us-east-1:xxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
$ AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx aws evidently list-features --project arc-editorial-search-api
{
"features": [
...
]
}
并使用 SDK:
import {
CognitoIdentityClient,
GetIdCommand,
GetOpenIdTokenCommand
} from '@aws-sdk/client-cognito-identity'
import {
STSClient,
AssumeRoleWithWebIdentityCommand
} from '@aws-sdk/client-sts'
import {
EvidentlyClient,
ListFeaturesCommand
} from '@aws-sdk/client-evidently'
;(async () => {
const cognitoClient = new CognitoIdentityClient({ region: 'us-east-1' })
const { IdentityId } = await cognitoClient.send(
new GetIdCommand({
AccountId: 'xxxxxxxxxxxx',
IdentityPoolId: 'us-east-1:xxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx'
})
)
const { Token: WebIdentityToken } = await cognitoClient.send(
new GetOpenIdTokenCommand({
IdentityId
})
)
const stsClient = new STSClient({ region: 'us-east-1' })
const {
Credentials: {
AccessKeyId: accessKeyId = '',
SecretAccessKey: secretAccessKey = '',
SessionToken: sessionToken = ''
} = {}
} = await stsClient.send(
new AssumeRoleWithWebIdentityCommand({
RoleArn:
'arn:aws:iam::xxxxxxxxxxxxx:role/my-iam-role',
RoleSessionName: 'test',
WebIdentityToken
})
)
if (accessKeyId && secretAccessKey && sessionToken) {
const evidentlyClient = new EvidentlyClient({
region: 'us-east-1',
credentials: {
accessKeyId,
secretAccessKey,
sessionToken
}
})
const featureResp = await evidentlyClient.send(
new ListFeaturesCommand({
project: 'arc-editorial-search-api'
})
)
console.log(featureResp)
}
})()