AWS is, at best, complicated. Part of that complexity is that there are often seems to be more than one way to accomplish a goal. Service policies and IAM permissions are a great example of this. Both seem to accomplish the same thing (permissions), but serve different purposes.
Where service policies define permissions on a single service (like an S3 bucket itself), IAM permissions describe what a user is allowed to do. Both use the same JSON format.
So when should one use a service policy versus IAM permissions?
The answer is that both are probably required! A service policy defines what/who may interact with a service. For example, an S3 bucket policy may say that it’s okay for another AWS account to access a bucket, but the actual entity touching that bucket will also need IAM permissions to do so.
Sometimes, however, IAM permissions are not necessary because the thing touching the service doesn’t have an IAM identity beyond what IAM itself calls a principal. For example an ECR repository policy may say, “It’s okay for AWS CodeBuild to get images from this repository.” CodeBuild itself may not have a specific IAM identity when its just pulling images. Similarly an SNS topic may trust CloudWatch to broadcast messages to it and no additional IAM permissions are required.1
Recap and TL;DR
- Service policies define who/what may interact with a service.
- IAM permissions define whether or not an entity (role, user, etc) is allowed to interact with a service.
- Both are often required! because they both serve different purposes. This is especially apparent in cross account situations.
Even the addition of service-linked roles does not mean that service policies are going away. They are still a key piece in the permission structure of AWS, especially for cross account access.
1. CloudWatch, interestingly, allows the use of an IAM role the alarms and such may assume to get permissions or a SNS topic policy that explicitly trusts CloudWatch. Two ways to do the same thing.