How to provide restricted & secure access to a third party, to your AWS accounts, using Attribute Based Access Control (ABAC)
Tags: aws, security, cloud
Published: 2022-05-21 11:47:29

Many Organizations work with different vendors or third parties, to provide or consume services or you may have outsourced your work completely to the vendor. Often there is a need for Organizations to provide access to their resources like server, storage, database etc. to third parties but then the questions comes “HOW to give them secure access?. The question becomes more important when your resources are on the cloud.

This blog post will showcase a secure solution to answer above question. There are services and features in AWS which can be leveraged to achieve the above goal. Services like IAM, Attribute Based Access Control (ABAC) are much powerful to help in this regard. IAM provides permissions and policies, allows switching between IAM roles, and other features.

For the scope of this blog, Attribute Based Access Control (ABAC), IAM Role & Switch role functionalities have been used to derive the solution. Here is how the solution looks like-

![Solution architecture — Attribute Based Access Control (ABAC)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2w6tculf2r8s60ngxif.png)

What is Attribute Based Access Control (ABAC) and how it is different from traditional Role Based Access Control (RBAC)?

> As per [AWS documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction_attribute-based-access-control.html) - “Attribute-based access control (ABAC) is an authorization strategy that defines permissions based on attributes. In AWS, these attributes are called tags. You can attach tags to IAM resources, including IAM entities (users or roles) and to AWS resources. You can create a single ABAC policy or small set of policies for your IAM principals. These ABAC policies can be designed to allow operations when the principal’s tag matches the resource tag. ABAC is helpful in environments that are growing rapidly and helps with situations where policy management becomes cumbersome.”

> While RBAC defines permissions based on a person’s job function, known outside of AWS as a role. Within AWS a role usually refers to an IAM role, which is an identity in IAM that you can assume. IAM does include managed policies for job functions that align permissions to a job function in an RBAC model. In IAM, you implement RBAC by creating different policies for different job functions. You then attach the policies to identities (IAM users, groups of users, or IAM roles). As a best practice, you grant the minimum permissions necessary for the job function. This is known as [granting least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). Do this by listing the specific resources that the job function can access. The disadvantage to using the traditional RBAC model is that when employees add new resources, you must update policies to allow access to those resources.

Here is what you need for this to get implemented:

1. an AWS account for the third party whom you want to give access to. Better to have a dedicated OU for the third party.
2. AWS account(s) which you want to give access of. OU strategy may differ per organization
3. IAM policies which need to be associated with IAM role for third parties

Below is what I have created for the purpose of this demo.

**Step 1: OU structure in AWS Organization**
An OU called ‘OU-3rd-party’ and an AWS Account underneath it, for the third party and another OU called ‘OU-development’ and an AWS account underneath for the development which belongs to the organization want to build their workload on.

> Both these are root accounts, hence MUST be restricted from giving access to anybody.

![AWS Organization structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dj1xrsxv399jb358615d.png)

Note there is no Service Control Policy (SCP) on the 3rd-party OU. I’ll explain later why

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e70t5eix3g80zjndzfni.png)

**Step 2: Create IAM users for third party**
Create an IAM user for the 3rd party, so that it can assume the IAM role from the development (or any other) AWS account(s) but only when the user and role tags match. The following policy allows a user to assume any role in your account with the `3rdPartyAccessRole` name prefix. The role must also be tagged with the same team tag as the user.

![IAM Policy called ‘assumerolepolicy-3rdparty’ for third party user](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9uyraxxaxfhz8wrrlgfi.png)

![3rd party IAM user with IAM policy attached](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6sq0r9oibo96hjvofw91.png)

![3rd party IAM user with tag](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prbanoadzd9dvomuoir9.png)
 
Now, login to the Development AWS account, in my case it is `836016191915`. An IAM role which needs to be assumed by the third party user is to be created.

**Step 3: Create ABAC Policy & IAM role to be assumed by the third party user, in the development account**
The following policy called `3rdparty-access-policy` allows principals to read secrets, start and stop EC2s but only when those resources are tagged with the same key-value pairs as the principal.

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "secretsmanagerreadonlyforsameteam",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:Describe*",
                "secretsmanager:List*",
                "secretsmanager:Get*"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/access-team": "${aws:PrincipalTag/access-team}"
                }
            }
        },
        {
            "Sid": "secretmanagerlistsecretsforAll",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetRandomPassword",
                "secretsmanager:ListSecrets"
            ],
            "Resource": "*"
        },
        {
            "Sid": "allowEC2startstopforsameteam",
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/access-team": "${aws:PrincipalTag/access-team}"
                }
            }
        },
        {
            "Sid": "describeEC2forAll",
            "Effect": "Allow",
            "Action": "ec2:DescribeInstances",
            "Resource": "*"
        }
    ]
}
```

Following IAM role `3rdPartyAccessRole` is created and the `3rdparty-access-policy` that was created in the previous step is attached to it. The role also needs to be tagged with the same tag as the resource and the principal tag.

![IAM role in the development account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ch6qxvytiuccvfxkxa7q.png)

![tag on the IAM role in the development account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3pl8poug726avoog2zjm.png)
 
All done now! It is the time to test.

Login to the AWS Console, with the third party IAM user created. In my case, it is the user `3rd-party-vendor-user`. Upon login, it doesn’t have access to any of the resources in its AWS account.

![No access to S3 service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hp4g1xqqyid3ssxhmzn.png)

![No access to EC2 service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ee3nxwqbtei7h0vjjhd2.png)

![No permission to access Secrets manager service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rswo1nvqwsx2clb79enj.png)
   
![No permission to access IAM service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63kjbsx94nki2i9seqnq.png)
 
Now lets ask the third party user to assume the role `3rdPartyAccessRole` from the development account `836016191915`via Switch role functionality OR the switch role link generated in the IAM role can be shared with them -
![Link to Switch role](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elysp0a7m6d79i368vbm.png)

I’ll use the Switch role option:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/906m47692l139zbtdlpc.png)
 
Enter the development account number, the IAM role created and the display name (optional) and click on Switch Role button:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w66nwt6scl00wxf6fuz9.png) 

Upon login, click the account information drop down to see additional details. Notice the ‘currently active as’ & ‘Account ID’ fields, it is the IAM role & the AWS Account ID, the 3rd party user assumed. To verify who has assumed the role, see the ‘Signed is as’ field below on the same panel.

![Switch role information](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dg3u1vkr6j90lrihfydd.png)

Now, lets test the permissions. While in the development account, third party user is allowed to list and get the value of only those secrets which are tagged as same as the user’s tag i.e. `access-team = 3rdpartyuser`. The policy also allows the third party user to start and stop only those EC2s which are tagged as same as the user’s tag.

OK. In the Secrets manager service, there are two secrets stored: First, the ‘demo-secret’ which **doesn’t have** the tag `access-team = 3rdpartyuser` which means the third party user can’t retrieve the password whereas the second secret, `secret-3rdparty` is accessible to the third party user. See the setup below:

![Secret in the ASM which can NOT be accessed by the third party user](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j6zfm2whlyfjjafy47mf.png)

![Secret in the ASM which can be accessed by the third party user](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m76vzbwnob76hlc1g12s.png) 

Third party user, as per the permissions, can list the secrets

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsyxhd3vhgdex82m3of3.png) 

When trying to access the demo-secret (remember it doesn’t have the same tag as the IAM user) it gets an error:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xj66kb19frcl9w5528p.png) 

Now, when accessing the second secret `secret-3rdparty`, it is able to retrieve the password successfully since the resource tag matches the principal tag:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hgr5ewuxlta9lxhv0kbk.png) 

Great! Lets test the EC2 permissions as well. In the Development account, there is one EC2 in stopped state and tagged as `access-team = aws-community-builder` which means logged in third party user should not be able to start this EC2.
![EC2 in Development account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1cbd27mlg20zvy8yxpzw.png) 

Lets see and as expected, it can not Start the instance:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jsyb4wm4inafxayxjo1l.png) 

They can verify why they can not access as the resource doesn’t belong to them:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5inl4ajjepd2zeuhwi6s.png) 

Well done! :)

Now, the answer why there is no Deny SCP buy still the third party user doesn’t have permissions to any AWS resources, is because an IAM principal is denied access by default, they must be explicitly allowed to perform an action. Otherwise, they are _**implicitly denied**_ access.

Here, the third party IAM user has explicit Allow in the Identity based policy, for `sts:AssumeRole` only, rest of the permissions are implicitly denied. Here is how the policy evaluation logic works:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ednocetvystsip4lp04a.png) 
*source: AWS documentation Policy evaluation logic

If your use case requires the use of AWS CLI or AWS API to assume that role then you can introduce more security by using the External ID;refer the documentation - https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html

If your company uses a SAML-based identity provider (IdP) to manage corporate user identities, you can use SAML attributes for fine-grained access control in AWS. Attributes can include cost center identifiers, user email addresses, department classifications, and project assignments. When you pass these attributes as session tags, you can then control access to AWS based on these session tags. Follow the AWS documentation [IAM tutorial: Use SAML session tags for ABAC](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_abac-saml.html).

With this blog post, I have showcased how you can provide secure access to the AWS resources in your AWS accounts, to the Third parties which require access to those AWS resources, through AWS Console, using attribute based access control.

---

I hope you have learned something from this blog post. If you liked reading this blog post, please clap and follow me for more interesting posts.

Till then Happy Learning!

Be AWSome! Be Happy! :)