launch fargate task with dynamic policy

Viewed 376

I would like to launch an ECS fargate TASK while granting dynamic permissions on the container. More specifically, I want the container to be able to access a single file in s3, which I only know about at runtime.

I tried to use sts:GetFederationToken to achieve the following (spoiler, it doesn't work):

enter image description here

  • lambda gets called with some fileName
  • lambda calls GetFederationToken with policy restriction on the specific s3 file
  • Obtain tokens and pass them to the container (using container overrides)

Unfortunately, this does not work and I'm stuck with the following error:

AccessDenied: Cannot call GetFederationToken with session credentials

From what I now understand, it appears that lambda is already using a temp session, and can therefore not call sts:GetFederationToken.

Is there any way to achieve what I'm trying to do here ? To recap, I would like a lambda to launch a fargate task that has access rights on a specific s3 file. I cannot know the s3 file in advance (i.e. I cannot create a proper policy beforehand)

EDIT

To clarify things a bit more:

  • I can NOT know the file name before the lambda is called. The file name depends on user parameters, and is sent to the lambda by the user, at runtime
  • Multiple containers will run at the same time, and no container should have permission to see anything else than its own legit file (i.e. containers cannot be trusted)
3 Answers

Given you only know the file beforehand, you need to pass the file name to the task at runtime - perhaps the cleanest way is to use 'ContainerOverides/Environment' to set a variable when calling the 'run_task' api.

You don't need to create a new task definition but you do need to do something.

There are a finite amount of realistic options, and you have to make a trade off.

Assuming the container task knows the file to read via it's environment, and assuming the file is in a bucket in the same account as the container and access is to be via an AWS sdk:

  • the task role can have s3:GetObject on a wildcard but the s3 bucket policy needs to grant access to the principal ( the task role )

  • if there is no access granted via a bucket policy, then the task role needs to have, or assume a role that has, specific access to the file via an identity policy.

If the s3 object is in a different account, both the bucket policy needs to give access to the principal and the task role need to give access to the object.

That's just how IAM works so you have to make some change to either the IAM policy on the ECS Task Role or the S3 Bucket policy before running the task.

GetFederationToken is not the right solution here-either you do the above or go down the road of using a pre signed url for the s3 object and having it access it over http - but i'm assuming an sdk is required

TLDR: I'd be looking to pass the file to read as an environment var and update the policy of the ecs task role though note that the task would retain access until the policy was amended unless the policy had a condition with an aws:CurrentTime clause

Can you create some sort of wildcard permission for the S3 file? If security is #1 priority on the files you can go a bit more advanced:

With the lambda you can create a custom policy (that allows access to that object in S3) and taskdefinition. Assign the taskpolicy to the taskdefinition and deploy the taskdefinition in the ECS service. Should all be possible with SDK.

One way to do it is the following, although I'm not sure it's very standard:

  • create a "broker" AWS user with wildcard permissions on s3 (and only that)
  • create static keys for the user, and store them in secrets manager
  • At runtime, lambda can read "broker's creds" and call federate identity to create a temporary session with restricted access on a specific s3 file
  • the temporary creds can be sent to the container instance using environment variables

enter image description here

It's basically the same approach than in the question, but this time we use static credentials rather than the lambda's assumed role to create the session.

I can tell for sure that it works, but I'm not quite sure it's the best way to do it.

Related