A lesson in IAM
IAM has a reputation for being a dark art. A lot of the time when things are not working as they should, a permission issue is at fault. Welcome to the world of IAM! It's the fibre that runs throughout the entire AWS ecosystem and if you work with AWS, there is no running away from it.
What is it?
AWS Identify and Access Management (IAM) enables you to manage identities and access AWS services and resources securely. It ensures only authorised users have access to your resources.
Policies
The controlling of these resources is done via policies. Each and every request to AWS goes through a check to determine if the principal is authenticated and authorised to the desired action.
A policy is an object in AWS that determines allow
and deny
actions for services and resources. deny
actions always override allow
actions by default.
I recently had the chance to help secure a fairly new service. Without going into too much detail, we needed to limit the attack surface area introduced via a wildcard permission.
Why is this bad?
It meant that any engineer on the team was able to wire up a function that could talk to the service directly and query data as they wish. We of course trust our engineers but one should always keep security best practices top of mind.
Plus, given this was one of our microservices, the service's interface should dictate how it's accessed and not be bypassed by another service or function.
Bad policy example
AccessPolicies:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action:
- 'cheese:CakeHttpGet'
- 'cheese:CakeHttpPut'
- 'cheese:CakeHttpPost'
Resource:
- !Sub 'arn:aws:es:${Region}:${AccountId}:domain/cheesecake-${Stage}/*'
Fixed (better) policy example
AccessPolicies:
Version: '2012-10-17'
Statement:
- Effect: Deny
Principal:
AWS: '*'
Action:
- 'cheese:CakeHttpGet'
- 'cheese:CakeHttpPut'
- 'cheese:CakeHttpPost'
Resource:
- !Sub 'arn:${AWS::Partition}:es:${Region}:${AccountId}:domain/cheesecake-${Stage}/*'
Condition:
StringNotEquals:
aws:PrincipalArn: !Sub 'arn:${AWS::Partition}:iam::${AccountId}:role/cheesecake-api-${Stage}-${Region}-lambdaRole'
What does this do?
You will notice that we retained the wildcard. When used with a deny
action it's incredibly helpful since by default we can block requests from all principals and then put in a condition for the principal who is actually allowed to make requests.
Let's say we have a disgruntled engineer who wants to add malicious code to query from this service. Originally, the engineer would have just created a Lambda function with a policy set up with allow
actions to access the above service. That Lambda could then query the data and manipulate it to its heart's content.
With the fixed resource policy, the service is now only accessible by the IAM role. It's a great start but more can be done such as the usage of a trust policy.
AWS Identity and Access Management is a core component to learn when working with AWS. Other attack vectors will always exist but it's important to do what you can to minimise risk. I'm personally a long way from mastering it but being exposed to lessons like these certainly helps!