1. All IAM policies/roles and InstanceProfile's should be managed in CloudFormation, no exception.
2. Policies should not be inlined into the IAM role policy document, rather they should be attached (excepting item 3 and 4).
3. IAM roles which are used for signing S3/CloudFront/... requests which are subsequently made public should should have all policies inlined AND the explicit resource should be defined.
4. IAM roles granting access to an external (non-AWS service) principal should generally inline all statements unless the relationship to the principal can be considered secure.
5. Policies should have multiple statements, one statement per AWS service.
6. Most non-administrative policies dealing with persistent storage (DynamoDB/S3) should be constrained to a limited number of resources.
7. Glob-Star is not permitted for any `Action` statement (ie: no `s3:*`).
8. Absolutely no AWS_ACCESS_KEY's are permitted on EC2 instances.
If via console, that gets done behind the scenes when attaching the role. But ya roles use the security token service behind the scenes which allow for temp creds vs. storing sensitive stuffs on the instances.
That being said, I've found IAM's power impressive but ultimately complex. If you're really serious about isolating users from certain resources, separate AWS accounts for each environment may well be the best way to do this. This way, you can grant "admin" access to users in your "stage" AWS account, they get all the permissions they need to do their work, and have no permissions to the more sensitive "prod" account.
Honestly, as a not-a-security-guy, I can count on the fingers of one hand the number of times I've had to learn something around security and it's been easy.
> separate AWS accounts for each environment may well be the best way to do this
A thousand times yes. There is so much to do in IAM, that it's just easier to let the devs have access to a 'test' account, and keep the 'prod' account out of their mitts.
It allows you to manage accounts via an API.
For IAM Roles, we use Infrastructure-as-Code (Terraform) to create all those anyway, so I still prefer to create those in the AWS account that contains the resources to which they apply.
[1] https://aws.amazon.com/blogs/security/enable-a-new-feature-i...
I'd be interested to see your team's workflow for multiple accounts @joshpadnick.
This significantly reduces the risk that an account-level problem or throttle will disrupt your entire business.
Fortunately, AWS finally seems to be getting serious about building management tools for multiple accounts. AWS Organizations is way better than the old consolidated billing stuff.
As for which direction, this is going to be a bit of preference and need. Do you want permissions to begin at the user or at the resource? For scenarios, like a bucket controlling access to non-aws users, it makes sense to have it on the resource. For others, like delegating bucket access to certain EC2 instances, it makes more sense to keep it on the role user.
The fuzzy lines of gray are only exaggerated by the fact that the docs love doing stuff like: "These two policies are equivalent!" And showing examples that accomplish both.
Tl;dr, (a) pick the permission direction that makes sense (b) set a standard for your team and infrastructure and stick with it (c) try to not use NotVersions of actions
- Granting cross-account access to resources without requiring an explicit sts:AssumeRole on the other side (in some cases for things like CloudTrail and billing reports this is the only option)
- Enforcing SSE on S3 buckets (implemented as a DENY in the bucket policy with conditions to check for missing SSE headers)
How do we maintain mental sanity? We define all our infrastructure on code (terraform) and we have found the right abstraction in the tool: modules. One module output is used as input on another module. Let's say you have a module to create and configure a bucket exporting the arn of the bucket, then another module to create the autoscaling-group along with its security groups, IAM Role and Policy. All changes are made through pull-requests and reviewed.
If you want to know who has access to a resource you read the dsl. I havent seen any tool to query aws api that way. It might be complex to build because policies can have all sort of wildcards.
We use 1 base policy + 1 policy/role, and so for each role it's easy to see what are its permissions.
We have no policy on resources, so it's hard, e.g., given a bucket to know who has access to it. We're building tooling for that.
edit: grammar/typos