While I was engaged in creating tests for our URL Filter Lambda at Qxf2, I encountered a problem related to an invalid security token. You can access the code for our URL Filter on GitHub through the following link here. If you encounter an error message stating “The security token included in the request is invalid” while using LocalStack, it typically indicates that your code is making requests to the AWS server instead of utilizing the LocalStack endpoint_url. For detailed information, please refer to the complete error message provided below.
{'errorMessage': 'An error occurred (InvalidClientTokenId) when calling the SendMessage operation: The security token included in the request is invalid', 'errorType': 'ClientError', 'stackTrace': ['File "/var/task/lambda_with_dependency.py", line 160, in lambda_handler\n write_message(reply, os.environ.get(\'ETC_CHANNEL\',\'\'))\n', 'File "/var/task/lambda_with_dependency.py", line 127, in write_message\n sqs.send_message(QueueUrl=QUEUE_URL, MessageBody=(message))\n', 'File "/var/task/botocore/client.py", line 337, in _api_call\n return self._make_api_call(operation_name, kwargs)\n', 'File "/var/task/botocore/client.py", line 656, in _make_api_call\n raise error_class(parsed_response, operation_name)\n']} |
This type of issue arises when there is an attempt to access one AWS service from another AWS service.
The security token issue is directly associated with credentials, and it’s important to note that LocalStack does not handle credentials. This means that somehow your code is making a call to either an AWS endpoint or an alternative endpoint, resulting in the error message of an invalid security token. To resolve this, please review your service client code and ensure that your code is making the call to the correct endpoint URL. If you did not specify the endpoint_url parameter when obtaining the client object, it indicates that your client is utilizing the default endpoint_url which points to the AWS endpoint.
How to fix the issue:
To resolve this type of issue, you need to provide the LocalStack endpoint URL when creating the client for the service. In my particular case, I encountered the error when using the following method to send a message to the SQS.
def write_message(message, channel): "Send a message to Skype Sender" sqs = boto3.client('sqs') print(channel) message = str({'msg':f'{message}', 'channel':channel}) print(message) sqs.send_message(QueueUrl=QUEUE_URL, MessageBody=(message)) |
In the code mentioned above, the SQS client was generated without explicitly passing the ‘endpoint_url’. As a result, ‘boto3’ utilized the default ‘endpoint_url’ which points to the AWS server. To resolve this issue, we need to pass the LocalStack ‘endpoint_url’ when running the code on LocalStack, and use the default ‘endpoint_url’ when running it on the AWS server. Please refer to the code changes we made to address this problem.
def write_message(message, channel): "Send a message to Skype Sender" # Check if running on localstack or production environment is_localstack = os.environ.get('LOCALSTACK_ENV') == 'true' if is_localstack: sqs = boto3.client('sqs',endpoint_url = 'http://localstack:4566') else: sqs = boto3.client('sqs') print(channel) message = str({'msg':f'{message}', 'channel':channel}) print(message) sqs.send_message(QueueUrl=QUEUE_URL, MessageBody=(message)) |
Now, when running Lambda on LocalStack, we need to set ‘LOCALSTACK_ENV’ to true. In this case, we use the LocalStack ‘endpoint_url’ (http://localstack:4566) while creating the SQS client. On the other hand, when running the code on AWS or in a production environment, there is no need to set ‘LOCALSTACK_ENV’.
Another additional change we need to make is to utilize the LocalStack ‘endpoint_url’ (http://localstack:4566) based on how you are running or deploying your LocalStack. Please refer to the LocalStack documentation mentioned here for more details.
In our case, we are running LocalStack using a docker-compose file and have implemented the following changes as recommended in the documentation.
services: localstack: # ... other configuration here environment: MAIN_DOCKER_NETWORK=ls networks: - ls networks: ls: name: ls |
I hope this blog post helps you understand the root cause of the issue and provides a solution to fix it.
Hire testers from Qxf2
Testers from Qxf2 can be your development team’s secret weapon. We go beyond traditional test automation, offering testing expertise in testing diverse technologies, including microservices, data pipelines, and AI/ML-based applications. Our extensive startup experience and innovative approaches enable us to solve important testing challenges at startups. We fill critical testing roles and adapt to rapid changes, offering tailored QA solutions for startups that keep pace with product evolution. Get in touch today!
I love technology and learning new things. I explore both hardware and software. I am passionate about robotics and embedded systems which motivate me to develop my software and hardware skills. I have good knowledge of Python, Selenium, Arduino, C and hardware design. I have developed several robots and participated in robotics competitions. I am constantly exploring new test ideas and test tools for software and hardware. At Qxf2, I am working on developing hardware tools for automated tests ala Tapster. Incidentally, I created Qxf2’s first robot. Besides testing, I like playing cricket, badminton and developing embedded gadget for fun.