mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-19 10:52:04 +00:00
223 lines
7.2 KiB
Markdown
223 lines
7.2 KiB
Markdown
---
|
|
title: "IAM Groups for Shared User Permissions"
|
|
description: "Organise AWS IAM users into groups, manage membership, and attach managed or inline policies once for the whole team instead of granting them user by user."
|
|
category: "Identity"
|
|
tags:
|
|
- iam
|
|
- groups
|
|
- users
|
|
- policies
|
|
- security
|
|
resources:
|
|
- title: "Spinifex Repository"
|
|
url: "https://github.com/mulgadc/spinifex"
|
|
- title: "AWS IAM Groups Documentation"
|
|
url: "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html"
|
|
---
|
|
|
|
# AWS IAM Groups for Shared User Permissions
|
|
|
|
> Organise AWS IAM users into groups, manage membership, and attach managed or inline policies once for the whole team instead of granting them user by user.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Prerequisites](#prerequisites)
|
|
- [Groups](#groups)
|
|
- [Membership](#membership)
|
|
- [Group Policies](#group-policies)
|
|
- [Putting It All Together](#putting-it-all-together)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
A group is a collection of [IAM users](/docs/iam-users-and-policies). Policies attached to a group apply to every member, so instead of attaching the same policy to each developer individually, you attach it once to a `developers` group and manage membership.
|
|
|
|
Members inherit both the group's **attached managed policies** and its **inline policies**, combined with any policies on the user itself. Policy evaluation is the same as everywhere else: an explicit `Deny` in any applicable policy wins, and anything not allowed is denied.
|
|
|
|
Groups cannot be nested, and a group is not a principal — it cannot sign requests or own access keys. The identity you assume to get credentials is an [IAM role](/docs/iam-roles-and-instance-profiles), not a group. Like all IAM resources, groups are scoped to the account that creates them.
|
|
|
|
## Prerequisites
|
|
|
|
- A running Spinifex cluster (see [Setting Up Your Cluster](/docs/setting-up-your-cluster))
|
|
- AWS CLI configured with the `spinifex` profile:
|
|
|
|
```bash
|
|
export AWS_PROFILE=spinifex
|
|
```
|
|
|
|
## Instructions
|
|
|
|
## Groups
|
|
|
|
### Create a Group
|
|
|
|
```bash
|
|
aws iam create-group --group-name developers
|
|
```
|
|
|
|
```json
|
|
{
|
|
"Group": {
|
|
"Path": "/",
|
|
"GroupName": "developers",
|
|
"GroupId": "AGPA1A2B3C4D5E6F7890",
|
|
"Arn": "arn:aws:iam::000000000001:group/developers",
|
|
"CreateDate": "2026-07-03T10:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
Use `--path` to organise groups hierarchically:
|
|
|
|
```bash
|
|
aws iam create-group --group-name ops --path /teams/
|
|
```
|
|
|
|
### Get and List Groups
|
|
|
|
`get-group` returns the group and its members:
|
|
|
|
```bash
|
|
aws iam get-group --group-name developers
|
|
aws iam list-groups
|
|
aws iam list-groups --path-prefix /teams/
|
|
```
|
|
|
|
### Delete a Group
|
|
|
|
A group must have no members and no policies before it can be deleted — see [Cleaning up a group](#deleteconflict-when-deleting-a-group).
|
|
|
|
```bash
|
|
aws iam delete-group --group-name developers
|
|
```
|
|
|
|
## Membership
|
|
|
|
Add and remove users:
|
|
|
|
```bash
|
|
aws iam add-user-to-group --group-name developers --user-name carol
|
|
aws iam remove-user-from-group --group-name developers --user-name carol
|
|
```
|
|
|
|
List a group's members (the `Users` array of `get-group`):
|
|
|
|
```bash
|
|
aws iam get-group --group-name developers --query 'Users[].UserName'
|
|
```
|
|
|
|
List the groups a user belongs to:
|
|
|
|
```bash
|
|
aws iam list-groups-for-user --user-name carol --query 'Groups[].GroupName'
|
|
```
|
|
|
|
> **Group membership blocks user deletion.** `delete-user` returns `DeleteConflict` while the user is still in any group — remove them from all groups first.
|
|
|
|
## Group Policies
|
|
|
|
### Attach a Managed Policy
|
|
|
|
```bash
|
|
aws iam attach-group-policy --group-name developers \
|
|
--policy-arn arn:aws:iam::000000000001:policy/EC2ReadOnly
|
|
|
|
aws iam list-attached-group-policies --group-name developers
|
|
|
|
aws iam detach-group-policy --group-name developers \
|
|
--policy-arn arn:aws:iam::000000000001:policy/EC2ReadOnly
|
|
```
|
|
|
|
See [IAM Users and Policies](/docs/iam-users-and-policies) for creating managed policies and the policy document format.
|
|
|
|
### Inline Group Policies
|
|
|
|
Inline policies live inside the group and are deleted with it:
|
|
|
|
```bash
|
|
aws iam put-group-policy --group-name developers \
|
|
--policy-name keypair-mgmt \
|
|
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ec2:CreateKeyPair","ec2:DeleteKeyPair"],"Resource":"*"}]}'
|
|
|
|
aws iam list-group-policies --group-name developers
|
|
aws iam get-group-policy --group-name developers --policy-name keypair-mgmt
|
|
aws iam delete-group-policy --group-name developers --policy-name keypair-mgmt
|
|
```
|
|
|
|
Members are authorised by the union of the group's attached and inline policies. A user in `developers` with the policies above can call `ec2:DescribeInstances` (via the attached `EC2ReadOnly`) and `ec2:CreateKeyPair` (via the inline policy), while anything not granted — say `ec2:RunInstances` — is denied.
|
|
|
|
## Putting It All Together
|
|
|
|
Onboard a team with shared permissions:
|
|
|
|
```bash
|
|
# 1. Create the group and grant it permissions
|
|
aws iam create-group --group-name developers
|
|
aws iam attach-group-policy --group-name developers \
|
|
--policy-arn arn:aws:iam::000000000001:policy/EC2ReadOnly
|
|
|
|
# 2. Create users and add them to the group
|
|
aws iam create-user --user-name carol
|
|
aws iam add-user-to-group --group-name developers --user-name carol
|
|
|
|
# 3. Create access keys and configure profiles as usual
|
|
aws iam create-access-key --user-name carol
|
|
|
|
# 4. Verify: carol can describe instances via group policy, nothing more
|
|
AWS_PROFILE=spinifex-carol aws ec2 describe-instances
|
|
AWS_PROFILE=spinifex-carol aws ec2 run-instances --image-id ami-123 --instance-type t3.micro
|
|
# ^ AccessDenied — not granted by the group
|
|
```
|
|
|
|
To change the whole team's permissions later, edit the group's policies once — no per-user changes needed.
|
|
|
|
## Troubleshooting
|
|
|
|
### DeleteConflict When Deleting a Group
|
|
|
|
The group still has members, attached policies, or inline policies. Empty it first:
|
|
|
|
```bash
|
|
# Members
|
|
aws iam get-group --group-name developers --query 'Users[].UserName'
|
|
aws iam remove-user-from-group --group-name developers --user-name carol
|
|
|
|
# Attached policies
|
|
aws iam list-attached-group-policies --group-name developers
|
|
aws iam detach-group-policy --group-name developers --policy-arn arn:aws:iam::000000000001:policy/EC2ReadOnly
|
|
|
|
# Inline policies
|
|
aws iam list-group-policies --group-name developers
|
|
aws iam delete-group-policy --group-name developers --policy-name keypair-mgmt
|
|
|
|
aws iam delete-group --group-name developers
|
|
```
|
|
|
|
### DeleteConflict When Deleting a User
|
|
|
|
Group membership counts as a subordinate entity, alongside access keys and attached policies. Find and leave the user's groups:
|
|
|
|
```bash
|
|
aws iam list-groups-for-user --user-name carol
|
|
aws iam remove-user-from-group --group-name developers --user-name carol
|
|
```
|
|
|
|
### NoSuchEntity
|
|
|
|
The group or user referenced does not exist — both `get-group` on a missing group and `add-user-to-group` with a missing user return this. Check spelling with `list-groups` / `list-users`.
|
|
|
|
### Member Still Denied After Attaching a Group Policy
|
|
|
|
Check the policy landed on the right group and the user is actually a member:
|
|
|
|
```bash
|
|
aws iam list-groups-for-user --user-name carol
|
|
aws iam list-attached-group-policies --group-name developers
|
|
aws iam list-group-policies --group-name developers
|
|
```
|
|
|
|
Remember an explicit `Deny` in any policy that applies to the user — their own or any of their groups' — overrides the `Allow`.
|