The principle of least privileged is king when it comes to managing access. It’s a simple approach. You give your users access to the services and the actions on those services that they need and nothing more. Importantly, this approach is critical for regulated environments, such as PCI DSS.
However, when we adopt an everything as code approach it can get more complicated. Similarly with automation, you end up with services calling other services. These services in term perform actions on your behalf.
How do you control that?
IAM and least privileged
The cunningly named Identity and Access Management, IAM, is AWS’s key tool for managing access. It offers a very rich policy for granular control of access. It should be your starting point for providing access to services. One of the key concept in IAM is roles. AWS services, such Lambda and EC2, can be assigned roles. In this way, the services you run can adopt a least privileged approach too.
AWS has added some additional controls to IAM specifically around services that perform actions on your behalf. New condition keys, such as
aws:CalledVia, make it easier to grant the least privileged access. Now you can provide access to the actions that a user can perform and separately to the subsequent actions taken by AWS services on your behalf.
What does it mean for me?
Let’s say for example that you launch EC2 instances via CloudFormation. Your users need permissions to both services. With this new condition, you can enforce that users launch EC2 only via CloudFormation without providing them direct permissions for EC2.
Another use case we often see is whitelisting access to the AWS console. Although we could enforce this through conditions, it caused problems with downstream services. These services were calling other services via the AWS API and were failing the whitelisting condition. Traditionally, we have had to use assumed roles to manage this. Now we can replace that with the
aws:ViaAWSService condition by adding the following policy to roles or groups (and plugging in your whitelisted IPs). This statement evaluates to true if the request is not made from the whitelisted IP or from an AWS service.
How do I use it?
Let’s step through an example for an auditing service using S3 for its audit logs. In this scenario, we have a service that is writing logs to S3. We want to allow a group of users to be able to query the contents of the files in an S3 bucket but not access the bucket directly.
The following policy will deny the user access to the bucket and the objects unless access is from Athena. The trick here is the use of
aws:CalledVia which specifies a list of services that will not be denied access. Note, following the least privileged model implemented by IAM, access still needs to be allowed by policy (and/or bucket policy) to Athena. Simply not being denied does not provide access (the default answer from IAM is always no!).
So, let’s test this! If I try and access the bucket via the console, I’m not allowed to do so.
Let’s hop into Athena and try and query files in the bucket.
As expected, it works. We can see results from an Athena query against file in the bucket.
Least privileged is your friend
IAM has always been a fantastic tool for implementing least privilege. It has, however, made a few actions tricky to manage. These new conditions are a fantastic addition. Services are currently being updated to support them so keep an eye on the latest support information in the IAM Global Condition documentation.
If you are looking to implement a least privilege approach in AWS or want a second pair of eyes on your implementation, please get in contact.