skip to Main Content

We currently use ABAC in AWS to allow our developers to manage resources which are tagged as owned by their team. This is done through a policy with a condition as below:

"Condition" : {
  "StringEquals" : {
    "aws:ResourceTag/team" : "${aws:PrincipalTag/team}"
  }
}

We have some developers who regularly work with multiple teams though; so the above doesn’t work so well for them.

If the issue were the other way around (i.e. we had resources managed by multiple teams) we could work around this like so (the pipes here are just included so we could use pipes around discreat values to avoid accidental substring matches; i.e. our resource would be tagged |TeamA|TeamB| and our user tagged TeamB).

"Condition" : {
  "StringLike" : {
    "aws:ResourceTag/team" : "*|${aws:PrincipalTag/team}|*"
  }
}

However, I can’t see a way to do this when we want a user to be in multiple teams, and thus access resources tagged with either TeamA or TeamB.

I’d like to avoid making the condition too scenario specific; i.e. we don’t want to have to update the policy defintions each time we setup a new team / anything like that.

I believe this could potentially be solved by using ForAnyValue:StringEquals if aws:PrincipalTag/team were an array… but I’ve not seen a way to define an array attribute against an account (also, this value comes from AD/AAD’s extensionAttribute1, so we’d need a way to convert it (split on delimiter) from a string to an array).

"Condition" : {
  "ForAnyValue:StringEquals" : {
    "aws:ResourceTag/team" : [${aws:PrincipalTag/team}] // <-- I know this isn't valid syntax
  }
}

2

Answers


  1. Chosen as BEST ANSWER

    It looks like there isn't a nice solution to this (thanks @jellycsc for confirming / your suggestion).

    Here's a really hacky solution to this issue... We're unlikely to use it as it's not clean / there's likely better compromises out there; but sharing this idea in case it's any help to others.

    Each team gets assigned a sequential number:

    Number Team
    1 TeamA
    2 TeamB
    3 TeamC
    4 TeamD

    When tagging a resource, we can say which team(s) can access that resource by putting a 1 in the position of the team(s) to allow; e.g. someone in TeamB or TeamD can access MyS3Bucket: MyS3Bucket.Tags[Team] = "0101"

    Then a user in TeamB would have their Team tag set to ?0?? (yes, counterintuitively a 0 says they're in the team, a question mark says they're not).

    We can then set the condition (using StringNotLike) as

    "Condition" : {
      "StringNotLike" : {
        "aws:ResourceTag/team" : "${aws:PrincipalTag/team}"
      }
    }
    

    This isn't a great solution as any time a new team's added we need to change our tags to include an additional character (though we can pre-empt this by using an oversized string to begin with; say if we're fairly confident we'll never have more than 32 teams). Worse, it's not very human readable nor intuitive... But technically it would do the job.

    Example truth table for our MyS3Bucket (0101) demo:

    PrincipalTag/team HasAccess Notes
    ???? No User isn't in any teams
    0??? No User in TeamA
    ?0?? No User in TeamB
    ??0? No User in TeamC
    ???? No User in TeamD
    00?? Yes User in Teams A & B
    0?0? No User in Teams A & C
    0??0 Yes User in Teams A & D
    000? Yes User in Teams A & B & C
    00?0 Yes User in Teams A & B & D
    0000 Yes User in Teams A & B & C & D

    (etc.)

    So the above solution allows ABAC access to be granted to no, one, some, or all teams, and allows developers to be members of no, one, some, or all teams.


  2. Implementing ABAC in AWS is frustrating, and frequently requires workarounds. I wish the AWS team can put more effort on ABAC and make it more user-friendly. Here is a workaround for your case. You can use multiple tags on the principle. For example,

    {
        "Version": "2012-10-17",
        "Statement":
        [
            {
                "Effect": "Allow",
                "Action": "...",
                "Resource": "...",
                "Condition":
                {
                    "StringEquals":
                    {
                        "aws:ResourceTag/team": "${aws:PrincipalTag/team1}"
                    }
                }
            },
            {
                "Effect": "Allow",
                "Action": "...",
                "Resource": "...",
                "Condition":
                {
                    "StringEquals":
                    {
                        "aws:ResourceTag/team": "${aws:PrincipalTag/team2}"
                    }
                }
            },
            {
                "Effect": "Allow",
                "Action": "...",
                "Resource": "...",
                "Condition":
                {
                    "StringEquals":
                    {
                        "aws:ResourceTag/team": "${aws:PrincipalTag/team3}"
                    }
                }
            }
        ]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search