我在使用 Cognito 凭证从 python 脚本连接到 AWS IOT 时遇到问题。我正在使用python中的AWS IOT SDK以及BOTO3软件包。这是我正在做的事情:
首先,我设置了一个 Cognito 用户池,其中包含几个具有用户名和密码的用户来登录。我还设置了一个 Cognito 身份池,并将我的 Cognito 用户池作为唯一的身份验证提供程序。我不提供对未经身份验证的身份的访问权限。身份池有一个身份验证角色,我只称之为"MyAuthRole",当我转到 IAM 时,该角色附加了两个策略:一个是默认策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": [
"*"
]
}
]
}
第二个是物联网访问策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "iot:*",
"Resource": "*"
}
]
}
接下来,我有 python 代码来使用我的 AWS IAM 账户凭证(访问密钥和私有密钥)来获取临时身份验证令牌,如下所示:
auth_data = { 'USERNAME':username , 'PASSWORD':password }
provider_client=boto3.client('cognito-idp', region_name=region)
resp = provider_client.admin_initiate_auth(UserPoolId=user_pool_id, AuthFlow='ADMIN_NO_SRP_AUTH', AuthParameters=auth_data, ClientId=client_id)
id_token=resp['AuthenticationResult']['IdToken']
最后,我尝试使用此令牌连接到 AWS IOT,使用此功能:
def _get_aws_cognito_temp_credentials(aws_access_key_id=None,aws_secret_access_key=None,
region_name='us-west-2',account_id=None,user_pool_id=None,
identity_pool_id=None,id_token=None):
boto3.setup_default_session(aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name = region_name)
identity_client = boto3.client('cognito-identity', region_name=region_name)
loginkey = "cognito-idp.%s.amazonaws.com/%s" % (region_name,user_pool_id)
print("loginkey is %s" % loginkey)
loginsdict={
loginkey: id_token
}
identity_response = identity_client.get_id(AccountId=account_id,
IdentityPoolId=identity_pool_id,
Logins=loginsdict)
identity_id = identity_response['IdentityId']
#
# Get the identity's credentials
#
credentials_response = identity_client.get_credentials_for_identity(
IdentityId=identity_id,
Logins=loginsdict)
credentials = credentials_response['Credentials']
access_key_id = credentials['AccessKeyId']
secret_key = credentials['SecretKey']
service = 'execute-api'
session_token = credentials['SessionToken']
expiration = credentials['Expiration']
return access_key_id,secret_key,session_token,expiration
最后,我创建了 AWS IOT 客户端并尝试像这样连接:
myAWSIoTMQTTClient = AWSIoTMQTTClient(clientId, useWebsocket=True)
myAWSIoTMQTTClient.configureEndpoint(host, port)
myAWSIoTMQTTClient.configureIAMCredentials(temp_access_key_id,
temp_secret_key,
temp_session_token)
myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1)
myAWSIoTMQTTClient.configureDrainingFrequency(2)
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)
log.info("create_aws_iot_client", pre_connect=True)
myAWSIoTMQTTClient.connect()
log.info("create_aws_iot_client", post_connect=True, myAWSIoTMQTTClient=myAWSIoTMQTTClient)
问题是它会pre_connect,然后挂起并最终超时。我收到的错误消息是这样的:
AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
我还在某处读到可能还有其他政策必须以某种方式附加:
"根据 HTTP 和 WebSocketClient 策略文档,为了验证 Amazon Cognito 身份以通过 HTTP 发布 MQTT 消息,您必须指定两个策略。第一个策略必须附加到 Amazon Cognito 身份池角色。这是之前在 IdentityPoolAuthRole 中定义的托管策略 AWSIoTDataAccess。
第二个策略必须使用 AWS IoT AttachPrincipalPolicy API 附加到 Amazon Cognito 用户。
但是,我不知道如何在 python 或使用 AWS 控制台中实现上述目标。
如何解决此问题?
你是对的,你错过的步骤是使用AttachPrincipalPolicy API(现在已经贬值,已被Iot::AttachPolicy取代)。
为此:
创建 IoT 策略(IoT 核心版>安全>策略>创建)
为策略提供您希望附加到该策略的任何用户拥有的权限,从您的代码中共享,这意味着只需复制第二个 IAM 策略。尽管您希望将其锁定在生产中!
使用 AWS CLI,您可以使用以下方法将此策略附加到您的认知用户:
aws iot attach-policy --policy-name <iot-policy-name> --target <cognito-identity-id>
在 aws-samples/aws-iot-chat-example 中有一个涉及更多 AWS 示例,但它是在 JavaScript 中。我无法在 Python 中找到等效项,但是无论使用哪种语言,Cognito/IAM/IoT 配置步骤和所需的 API 调用都将保持不变。