Will
11/02/2021, 8:08 PMIf not provided, the default on the agent will be used (if configured).
). This does not happen for the task role, which is instead passed from the agent. This behaviour is unexpected; I would have assumed when passing a custom task definition, that the roles I have defined (task role and execution role) would not be overridden by prefect.
So, I've now modified naming convention for the task role for a particular flow, to test passing it via:
`task_role_arn (str, optional)`: The name or full ARN for the IAM role to use for this task. If not provided, the default on the agent will be used (if configured).
The role I have passed has full S3 permissions:
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
The flow itself uses the [S3Upload](https://docs.prefect.io/api/latest/tasks/aws.html#s3upload) action.
It fails with Error uploading to S3: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
Will
11/02/2021, 8:12 PMAnna Geller
Anna Geller
Kevin Kho
task_role_arn
and execution_role_arn
defined in the RunConfig. If there is none, it pulls the one defined on the agent. Are you saying you are seeing different behavior? Or are you saying this is unexpected?Kevin Kho
Anna Geller
task_definition
to your ECSRun, then all values including the task role and execution role, will be taken from this task definition, not from the agent or other run config kwargs,
• if you don’t provide a custom task definition, Prefect will create and register a new task definition (or a new revision of it) for you, based on the kwargs you provided to the ECSRun
such as the task_role_arn
and execution_role_arn
- if those are not passed to the ECSRun, then Prefect will take those defined on the agent.
So a custom task definition takes priority, then other ECSRun overrides, and if there are no overrides, the default values are taken from the agent definition. Does it make sense?
I think, if you would provide a custom task definition, and on top of that specify task_role_arn and execution_role_arn, then there is ambiguity as to which of those values should the agent take when registering a new task definition for a flow.Will
11/03/2021, 3:59 PMRunTask
call receives the new roles as overrides
, which should mean that they will take precedent over anything previously defined in the task definition.
https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html#ECS-RunTask-request-overrides
However, I've just retested and confirmed that the execution role does not get overridden by the execution role from the agent. I've verified by passing a parameter to the secrets
argument in the container definition:
https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html
The agent role doesn't have any secrets manager IAM permissions. The execution role on the custom task definition does; for this specific secret it has the secretsmanager:GetSecretValue
permission. When I run the flow it is able to retrieve the secret and inject it as an environment variable.
When I remove the permission from the custom task definition's execution role, and try to run the flow, it fails with:
ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve secret from asm: service call has been retried 1 time(s): failed to fetch secret arn:aws:secretsmanager:us-east-1...
So clearly something isn't working as expected here. This is just the execution role behaviour.Will
11/03/2021, 4:00 PMtask_definition
, task_definition_path
, task_definition_arn
, task_role_arn
or execution_role_arn
are defined on the run config, both execution and task roles should be copied from those applied to the agent. I haven't verified this.
1. If there is a custom task definition (task_definition
, task_definition_path
or task_definition_arn
), then according to https://github.com/PrefectHQ/prefect/blob/e699fce534f77106e52dda1f0f0b23a3f8bcdf81/src/prefect/agent/ecs/agent.py#L454-L464 the custom task definition's execution and task roles should both be overridden by those found on the agent.
As described above, this is definitely not happening for the execution role, and I can't figure out why not; the AWS api docs indicate that it should function as intended.
As for the task role, it is overridden by the prefect agent's role in this case.
1. If task_role_arn
or execution_role_arn
are set, these should take priority.
I can confirm from looking at the output of DescribeTasks
that the task role passed here is successfully applied to the running task.Will
11/03/2021, 4:00 PMS3Upload
task is incorrectly propagating boto credentials. If I were to take a guess at what is happening, it would be something to do with the caching behaviour in https://github.com/PrefectHQ/prefect/blob/ca19b43947eb16e36fe9ea777e4e65c15baaf0b8/src/prefect/utilities/aws.py#L23-L129
I am using the S3Upload
task like so (following the docs example, and simplified):
python
import prefect
from prefect import Flow
from prefect.tasks.secrets import EnvVarSecret
from prefect.tasks.aws.s3 import S3Upload
@task
def test_s3(s3_bucket: str):
logger = prefect.context.get("logger")
s3 = boto3.client("s3")
list_buckets_response = s3.list_buckets()
<http://logger.info|logger.info>(f"Buckets: {[x['Name'] for x in list_buckets_response['Buckets']]}")
res = s3.put_object(
Bucket=s3_bucket, Key="test.json", Body=b'{"hello": "world"}'
)
upload_task = S3Upload()
with Flow("hello_world") as flow:
s3_bucket = EnvVarSecret("S3_BUCKET", raise_if_missing=True)
test_s3(s3_bucket)
upload_task('{"hello": "world"}', key="data.json", bucket=s3_bucket)
if __name__ == "__main__":
flow.run()
test_s3
completes successfully. upload_task
fails with the PutObject
access denied exception detailed above.Kevin Kho
Will
11/03/2021, 4:03 PMS3Upload
is not correctly propagating credentials in the ECS task environment, when boto calls work correctly
Additionally, while not really a bug, I think it should work the way @Anna Geller describes, with a custom task definition taking priority over everything else. The current behaviour is unintuitive. This is obviously not a bug as it's in the docs 😛Will
11/03/2021, 4:04 PMprefecthq/prefect:0.15.6-python3.9
Kevin Kho
Will
11/04/2021, 10:56 AMECSRun
config instead of a full ARN, you can't do this for the task_role_arn
- even though it's specified in the Prefect docs that you can.
https://docs.prefect.io/api/latest/run_configs.html#ecsrun
See the parameter in here that it is passed to directly:
https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_TaskOverride.html
This is quite a problem for us and will require a rework of how we usually deploy resources to be shared across the org. We use AWS Organizations, so each developer gets their own AWS account and we have a few for different environments. If it were possible to not have to pass a full ARN here, we would not be restricted on an account basis; so could share flows between the different accounts quite simply.
It's still possible to do but will require a lot more fiddling!Anna Geller
family
, family:version
, or a full task definition ARN).
Should be changed to:
`task_definition_arn (str, optional)`: A pre-registered task definition ARN to use - a full task definition ARN is required.
Correct?Anna Geller
Anna Geller
Will
11/04/2021, 11:34 AMtask_definition_arn
. The description for task_role_arn
is not correct:
`task_role_arn (str, optional)`: The name or full ARN for the IAM role to use for this task. If not provided, the default on the agent will be used (if configured).Only the full ARN will work here.
Anna Geller
task_role_arn="arn:aws:iam::XXX:role/prefectTaskRole"
works, but you’d prefer to only specify task_role_arn="prefectTaskRole"
Anna Geller
Will
11/04/2021, 12:46 PMWill
11/04/2021, 12:48 PMrun_task
). It may be worth making a separate issue for this, I'm happy to do so if that's ok with you.
EDIT: As I did not define a default role for flows on the agent (I missed that I didn't do this), this behaviour is expected.Anna Geller
Anna Geller
import boto3
from prefect import task
@task
def upload_file(file_name, bucket, object_name):
s3_client = boto3.client("s3")
s3_client.upload_file(file_name, bucket, object_name)
Will
11/04/2021, 1:07 PMAlex Dancho
01/25/2022, 1:39 AMAnna Geller