Ordinarily, chalice deploy finds IAM permissions required for the application to work, builds an IAM role and prompts the user for authorization to add necessary permissions to the role:
$ chalice deploy
Regen deployment package.
The following actions will be added to the execution policy:
s3:GetObject
Would you like to continue? [Y/n]:
However, in some situations, the required permissions are not discovered and the app is deployed without the required permissions, resulting in botocore.exceptions.ClientError (AccessDenied) when a request is received.
In the example below, the app is deployed with a role that is missing the permissions that it requires.
app.py:
import boto3
from chalice import Chalice
app = Chalice(app_name='bug')
s3 = boto3.client('s3')
app.debug = True
@app.route('/')
def index():
data = get_content('foo')
return {'data': data.decode()}
def get_content(key):
content = s3.get_object(Bucket='this-chalice-resembles-a-grail',
Key=key)['Body'].read()
return content
I can confirm as well. I was even just doing this:
from chalice import Chalice
import boto3
app = Chalice(app_name='pycascades')
ec2 = boto3.client('ec2')
@app.route('/')
def index():
return get_regions()
def get_regions():
return ec2.describe_regions()
I get prompted correctly for policy generation for this though:
from chalice import Chalice
import boto3
app = Chalice(app_name='pycascades')
ec2 = boto3.client('ec2')
def get_regions():
return ec2.describe_regions()
@app.route('/')
def index():
return get_regions()
It looks like if the function gets defined before the index() function, it fails to traverse through the get_regions() function as it has yet to have the AST node registered to the get_regions symbol.
It looks like s3.upload_file is not detected at all even if it's in index(). Is there a workaround in the meantime? Because as it is now, even when I edit the policy manually, the next deployment will prompt me to overwrite it and there doesn't seem to be a way to skip the overwrite.
@weilu You can specify a role manually and tell Chalice to stop overwriting it.
Here's an example that may help with editing your .chalice/config.json file:
{
"version": "2.0",
"app_name": "example-app",
"manage_iam_role": false,
"iam_role_arn": "arn:aws:iam::424242424242:role/service-role/S3_read_access",
"stages": {
"dev": {
"api_gateway_stage": "api"
}
}
}
Replace 424242424242 with your account number.
Replace S3_read_access with your service role name.
Replace example-app with your app name.
When manage_iam_role is set to false, Chalice will not auto-generate a new role.
We had the same issue with Chalice. It didn't discover all required permissions. We spent a fair amount of time testing different ideas and suggestions. We were not able to get Chalice to cover all permissions. And also the manual policy creation is not a viable option for our purpose.
Finally, I found a workaround that did the trick for us. But be warned: it is very ugly :)
We handpicked all the boto3.client('s3') functions we need/call in the API.
And created a dummy function like
def dummy():
"""
Collection of all s3.client() functions.
The sole purpose is to force Chalice to generate the right permissions in the policy.
Does nothing and returns nothing.
"""
s3 = boto3.client('s3')
s3.put_object()
s3.download_file()
s3.get_object()
s3.list_objects_v2()
s3.get_bucket_location()
Then "call" the dummy in the root route, and make sure it will never be called, like:
@app.route('/')
def index():
if False: # make this to never evaluate as True
dummy()
...
Without changing any settings in the config, all required permission magically appeared in the autogenerated policy after deploy.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject"
],
"Resource": [
"*"
],
"Sid": "..."
}
]
}
@weilu You can specify a role manually and tell Chalice to stop overwriting it.
Here's an example that may help with editing your
.chalice/config.jsonfile:{ "version": "2.0", "app_name": "example-app", "manage_iam_role": false, "iam_role_arn": "arn:aws:iam::424242424242:role/service-role/S3_read_access", "stages": { "dev": { "api_gateway_stage": "api" } } }Replace
424242424242with your account number.
ReplaceS3_read_accesswith your service role name.
Replaceexample-appwith your app name.When
manage_iam_roleis set tofalse, Chalice will not auto-generate a new role.
This role has to be a different role though, right? Saying I want to keep the current role but just stop updating it is not an option. When I set the this in my config, Chalice fails to deploy because it cannot delete the current role (the one I want to keep but not update). Of course it cannot delete the role because there are policies attached to it.
Hello. It's been over 2 years since the bug was reported. Do you have any ETA for the fix or do we still need to use workarounds?
Bumping this. We have a scenario where we are configuring a few different things when the app starts up, including fetching the name of a resource. The endpoint can't seem to figure out that it needs the access to do that....
Fixed via https://github.com/aws/chalice/pull/1628
Still seem to be running into this issue with chalice 1.22.2, python 3.6.9, linux 4.15.0-136-generic. Don't have a code snipped ready to publish, but chalice suddenly stopped detecting my s3 upload_file() call through boto3... Not sure why, it also seems to fail even on previous commits where it had been working. Seems like there is a cache somewhere I need to clear? Tried deleting old deployments, removing __pycache__ dir, still seems to fail..
Seems like chalice won't detect s3 permissions if you use a factory method with a global variable for injecting a stub, like in the last example here: https://aws.amazon.com/blogs/developer/introducing-the-new-test-client-for-aws-chalice/.
Most helpful comment
We had the same issue with Chalice. It didn't discover all required permissions. We spent a fair amount of time testing different ideas and suggestions. We were not able to get Chalice to cover all permissions. And also the manual policy creation is not a viable option for our purpose.
Finally, I found a workaround that did the trick for us. But be warned: it is very ugly :)
We handpicked all the boto3.client('s3') functions we need/call in the API.
And created a dummy function like
Then "call" the dummy in the root route, and make sure it will never be called, like:
Without changing any settings in the config, all required permission magically appeared in the autogenerated policy after deploy.