Search code examples
amazon-web-servicesaws-lambdaaws-iotaws-iot-core

How to call IoT Core registerThing for another account?


I have a lambda. This lambda creates a thing by doing something like:

const cfnThing = new iot.CfnThing(this, 'MyCfnThing', /* all optional props */ {
  attributePayload: {
    attributes: {
      attributesKey: 'attributes',
    },
  },
  thingName: 'thingName',
});

But I want to create a thing on a different account. I created a role so it can be assumed. But I don't understand how to change credentials for the thing creation operation. I found that for s3 operations it can be done by putting new credentials to the client. Is there a client for iot too? Is there any other way to do that?


Solution

  • You first need to create a role in the destination account. Then in your lambda, in source account, you need to assume the role. Here is a piece of code I'm using to assume the role with automatic refresh of the credentials:

    This is the credentials.py:

    import boto3
    from botocore.credentials import RefreshableCredentials
    from boto3 import Session
    from botocore.session import get_session
    
    
    
    def refreshed_session(role_arn, region='eu-central-1'):
        """Assume a boto3.Session With automatic credential renewal.
        Args:
            region (str, optional): The region of the session.
                                    Defaults to 'eu-central-1'.
        Returns:
            session (Session): an boto3 session with RefreshableCredentials
        """
        def _refresh():
            " Refresh tokens by calling assume_role again "
            params = {
                "RoleArn": role_arn,
                "RoleSessionName": "cross_acct_lambda",
                "DurationSeconds": 3600,
            }
            sts_client = boto3.client("sts", region_name='eu-central-1')
            response = sts_client.assume_role(**params).get("Credentials")
            credentials = {
                "access_key": response.get("AccessKeyId"),
                "secret_key": response.get("SecretAccessKey"),
                "token": response.get("SessionToken"),
                "expiry_time": response.get("Expiration").isoformat(),
            }
            return credentials
    
        session_credentials = RefreshableCredentials.create_from_metadata(
            metadata=_refresh(),
            refresh_using=_refresh,
            method="sts-assume-role",
        )
    
        session = get_session()
        session._credentials = session_credentials
        session.set_config_variable("region", region)
    
        return Session(botocore_session=session)
    

    And then in lambda you can use it like this:

    # create service client using the assumed role credentials, e.g. iot-data
    boto3_session = credentials.refreshed_session(account_destination_role_arn)
    iot_client = boto3_session.client('iot-data')
    

    Any call to AWS IoT Control Plane API using iot_client will be on the destination account.