Skip to content

MWAA — can a single IAM role resolve to different Airflow RBAC roles per request, or is one IAM role per Airflow role required?

1

I'm building a FastAPI service that redirects authenticated users into the MWAA Airflow UI, scoped to the DAGs their team should see. I want to confirm the right IAM structure before building it out.

Environment

  • MWAA, Apache Airflow 3.2.1
  • Webserver access mode: Public
  • Region: us-east-1

What already works

I have per-DAG scoping working. Two custom Airflow roles, each created by copying Viewer and swapping the global can read on DAGs / can edit on DAGs permissions for per-DAG ones:

LocationalOperator: can read/edit on DAG:location_test_dag
FinancialOperator:  can read/edit on DAG:financial_test_dag

An IAM user with airflow:CreateWebLoginToken scoped to arn:aws:airflow:us-east-1:<account-id>:role/<env-name>/Public, with the custom role attached to the auto-provisioned Airflow user record, correctly sees only its own DAG. That part is confirmed working.

What I'm trying to do next

Move from an IAM user to an IAM role, so the same flow works from a service (Lambda for the POC, FastAPI on ECS in production). The service receives the user's group membership from SSO in a JWT claim, and needs to mint a web login token that resolves to the matching Airflow role.

The question

create_web_login_token accepts only the environment name — there's no parameter for which Airflow role the session should resolve to. As I understand it, the Airflow role comes from the role segment of the resource ARN in the IAM policy attached to the calling principal, and that ARN is static per policy.

So:

  1. Is it possible for a single IAM role to resolve to different Airflow RBAC roles depending on the request, or is the mapping necessarily fixed by the resource ARN in that role's policy?
  2. If it's fixed, is the correct pattern one IAM role per Airflow role (e.g. mwaa-locational-role, mwaa-financial-role), with the calling service using sts:AssumeRole to pick the right one based on the user's group claim?
  3. The five default Airflow roles are the only values supported in the resource ARN. With every user's policy pointing at Public, the custom role on the Airflow user record supplies the actual DAG permissions. Does this mean a per-user Airflow record is always required, and there's no way to have an IAM role alone carry a custom Airflow role?
  4. If separate IAM roles per team are the answer, does that scale reasonably to a larger number of teams, or is there a recommended alternative pattern for multi-tenant DAG access?
  5. Is there any supported way to pass the intended Airflow role as a request-time parameter that I may have missed?

Why it matters

If one IAM role can't serve multiple Airflow roles, the service needs an assume-role step and a role-per-team IAM structure, which changes how we provision teams. I'd rather confirm the intended pattern than build around an assumption

2 Answers
0

The supported pattern is one IAM role per Airflow role, with your service assuming the correct role at request time. Custom Airflow roles always require a per-user Airflow record; IAM alone cannot carry them.

https://docs.aws.amazon.com/mwaa/latest/userguide/security-iam.html

https://docs.aws.amazon.com/mwaa/latest/userguide/security_iam_service-with-iam.html

EXPERT

answered a month ago

0

Hi Malhar,

You asked to confirm rather than assume, so I'll separate what the documentation states from what I'm inferring, and give you a test that settles the open part in about ten minutes.

Direct answers first:

  1. Probably yes, but not through the IAM policy — and your premise about why it's fixed is the part I'd revisit. See below.
  2. Role-per-Airflow-role works, but it may not be necessary, and it's not the only way to vary the identity.
  3. Yes, confirmed. A per-identity Airflow user record is always required for custom roles. IAM alone cannot carry one.
  4. Role-per-team scales poorly past a few dozen teams. There's a better shape, and the AWS-published automation pattern has a caveat that matters for you specifically.
  5. No, confirmed — nothing exists and you didn't miss it.

Your premise is slightly off, and it changes the answer

You wrote that the Airflow role comes from the resource ARN and "that ARN is static per policy". The first half is only true for the five default roles, and the second half isn't the binding constraint.

Two separate mechanisms are in play, and conflating them is what makes this look unsolvable:

Mechanism A — resource ARN → default role. The role/<env>/<airflow-role> segment selects which of Admin, Op, User, Viewer, Public the session gets. Only those five are valid values (Accessing an Amazon MWAA environment). Note the tutorial's wording: MWAA maps IAM principals to "one or more" default roles, so a policy can list several. But that doesn't give you request-time selection: per this re:Post article, when the resource is ambiguous ("Resource": "*") MWAA "defaults to the most restrictive role". Resolution is deterministic, not selectable.

Mechanism B — IAM identity → Airflow user record → custom role. Your custom roles don't come from IAM at all. They're attached to the auto-provisioned Airflow user record, and MWAA does not strip them. From Tutorial: Restricting an Amazon MWAA user's access to a subset of DAGs:

Any of the 5 default roles (such as Admin) not authorized by IAM which are added using the Apache Airflow UI will be removed on next user log-in.

Only the five default roles get reconciled against IAM on each login. Custom roles survive — which is exactly why your working setup works, and it's worth understanding that it works by omission rather than by design.

So the real question isn't "can one IAM role point at several Airflow roles". It's "can one IAM role produce several distinct Airflow user records?" Because each record can carry a different custom role.

Why I think the answer is yes

CreateWebLoginToken returns two identity fields that are rarely looked at:

  • AirflowIdentity — "The user name of the Apache Airflow identity creating the web login token." Max length 64.
  • IamIdentity — "The name of the IAM identity creating the web login token. This might be an IAM user, or an assumed or federated identity. For example, assumed-role/Admin/your-name."

That example is the interesting part. For an assumed role the identity MWAA sees is assumed-role/<RoleName>/<SessionName> — it includes the role session name. The tutorial separately shows the Airflow user's name following the IAM principal name in the pattern user/mwaa-user, i.e. the Airflow record is derived from the identity string.

If the derivation includes the session name, then one IAM role assumed with N different RoleSessionName values yields N distinct Airflow user records, each independently assignable a different custom role. One IAM role, request-time selection, no role-per-team sprawl.

I want to be clear that this is an inference from the documented IamIdentity format, not a documented guarantee. But it's cheap to verify, and MWAA hands you the answer directly.

The decisive test

Assume your single role twice with different session names, and compare what MWAA reports back:

# Session 1
aws sts assume-role \
  --role-arn arn:aws:iam::<account-id>:role/mwaa-multitenant \
  --role-session-name locational-team
# export the three credentials, then:
aws mwaa create-web-login-token --name <env-name> \
  --query '{airflow:AirflowIdentity, iam:IamIdentity}'

# Session 2 — same role, different session name
aws sts assume-role \
  --role-arn arn:aws:iam::<account-id>:role/mwaa-multitenant \
  --role-session-name financial-team
aws mwaa create-web-login-token --name <env-name> \
  --query '{airflow:AirflowIdentity, iam:IamIdentity}'

If the two AirflowIdentity values differ, you're done: log in once with each so MWAA provisions both records, attach LocationalOperator to one and FinancialOperator to the other, and your service picks the tenant by setting RoleSessionName from the SSO group claim. If they're identical, the session name is discarded and you fall back to role-per-team as in your question 2.

Please post the result either way — this isn't documented anywhere I can find, and it's the crux of the question.

Two things to get right if it works

Set the session name from the validated claim, never from anything user-supplied. With this design the session name is the authorization decision, so a caller who can influence it can choose their tenant. Constrain it in the role's trust policy with the sts:RoleSessionName condition key so even a compromised service can only mint session names from an allowlist. That gives you defence in depth rather than relying solely on your FastAPI code being correct.

Mind the 64-character limit on AirflowIdentity, since assumed-role/<RoleName>/<SessionName> has to fit whatever transformation MWAA applies.

New session names provision empty records. A previously unseen session name creates an Airflow user with only the IAM-derived default role and no custom role, so it sees nothing until someone attaches the custom role. That's an argument for a fixed, small set of session names — one per team — rather than one per end user. Which is what you want anyway: the record count scales with teams, not with headcount.

Where I'd extend the other answer

The other answer's two claims are directionally right, and the second one is straightforwardly correct — custom roles do require a per-user Airflow record, and IAM cannot carry them. That's confirmed twice over: by the tutorial, and explicitly in this AWS Big Data blog: "IAM Based access control to Amazon MWAA works for Apache Airflow default roles. For custom roles, the Admin user can assign the custom role using the Apache Airflow UI."

Where I'd push back is on "the supported pattern is one IAM role per Airflow role" being presented as settled. Nothing in the two linked pages establishes that a single IAM role cannot serve multiple Airflow identities, because neither page addresses session-name derivation at all. It's a reasonable default assumption, but it's the assumption you said you didn't want to build on, and it's testable.

Question 5, definitively: no request-time parameter

Confirmed from the API reference. CreateWebLoginToken takes exactly one URI parameter, the environment Name, and "The request does not have a request body". There is no field for an intended Airflow role, and no undocumented one to find. Your reading was right.

Question 4, scaling

Role-per-team. The default quota is 1,000 IAM roles per account (raisable to 5,000), so you won't hit a hard wall, but you will get a role and policy to provision, review and audit per team, plus a trust-policy edit on every team change. Fine at ten teams, tiresome at fifty.

Single role, session-name-per-team. If the test above passes, this collapses the IAM surface to one role and one trust policy. Team onboarding becomes "add a session name to the allowlist and attach a custom role to the new Airflow record" — no IAM change at all.

Automating the Airflow side. This is where the real toil is: each new team needs a custom role created by copying Viewer, then per-DAG permissions maintained as DAGs come and go. AWS published a tag-based automation for exactly this in the blog linked above, where DAG tags drive role permissions on a schedule.

Read this caveat before you invest in it: that solution's own prerequisites state it requires "version 2.7.2 or later, not supported in Airflow 3.0". You're on 3.2.1, so it does not apply to you as written. The implementation writes directly to the FAB metadata tables (ab_role, ab_permission_view_role) from inside a DAG, and Airflow 3 isolates task code from the metadata database — task execution goes through the Task Execution API rather than holding a DB session. That's my explanation for the incompatibility rather than something AWS states, but either way the stated support boundary excludes your version. The idea still transfers; you'd need to drive the same permission updates from outside the environment instead of from a DAG.

Hard multi-tenancy. If teams must not share an environment at all, separate MWAA environments give you real isolation at real cost. Worth naming as the boundary of the RBAC approach rather than something to reach for first.

Airflow 3.2.1 specifics for the redirect service you're building

Three things that will affect your FastAPI implementation, from the re:Post article above:

  • The login path changed in MWAA 3.x. It's now /pluginsv2/aws_mwaa/login, not the 2.x /aws_mwaa/login. The REST API base also moved from /api/v1 to /api/v2. If you've been following 2.x examples, this is the first thing that will break.
  • The flow is create_web_login_token → GET https://{WebServerHostname}/pluginsv2/aws_mwaa/login?token={WebToken} with redirects disabled → read the _token cookie from the response. The article has a complete working Python example.
  • Sessions cache the role mapping. "Existing sessions use the old role mapping, so you must create a new session after updating the IAM policy." For you this means a user's tenant is fixed for the life of their session, so switching tenants requires minting a fresh token, not reusing the cookie.

Also: don't use "Resource": "*" anywhere in this policy, for the reason above — MWAA resolves it to the most restrictive role and you'll spend an afternoon debugging a Forbidden that has nothing to do with your code.

One last practical note: the web login token is short-lived and intended for immediate exchange, so mint it inside the request that redirects rather than caching it. I haven't verified the exact TTL, so measure it before you build retry logic around it.

Post back the two AirflowIdentity values from the test and I'll help you work through whichever branch you land in.

AWS

answered 19 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.