diff --git a/docs/identity/iam-groups/README.md b/docs/identity/iam-groups/README.md new file mode 100644 index 000000000..4e241e2f8 --- /dev/null +++ b/docs/identity/iam-groups/README.md @@ -0,0 +1,222 @@ +--- +title: "IAM Groups" +description: "Organise IAM users into groups and manage permissions once for the whole team." +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" +--- + +# IAM Groups + +> Organise IAM users into groups and manage permissions once for the whole team. + +## 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. 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. Like all IAM resources, groups are scoped to the account that creates them. + +## Prerequisites + +- A running Spinifex cluster with the AWS gateway started +- AWS CLI configured with your account's profile. The default `spinifex` account created at cluster setup works out of the box; to work in a separate account, create one with `spx admin account create` (see [Spinifex Admin CLI](/docs/spinifex-admin-cli)): + +```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`. diff --git a/docs/identity/iam-roles-and-instance-profiles/README.md b/docs/identity/iam-roles-and-instance-profiles/README.md index 49275d9ef..bae696815 100644 --- a/docs/identity/iam-roles-and-instance-profiles/README.md +++ b/docs/identity/iam-roles-and-instance-profiles/README.md @@ -33,7 +33,6 @@ resources: - [Managing Profile Associations at Runtime](#managing-profile-associations-at-runtime) - [Assuming a Role](#assuming-a-role) - [Cleaning Up](#cleaning-up) -- [Command Reference](#command-reference) - [Troubleshooting](#troubleshooting) --- @@ -51,11 +50,10 @@ Like all IAM resources, roles and instance profiles are scoped to the account th ## Prerequisites - A running Spinifex cluster with the AWS gateway started -- An account created via `spx admin account create` (see [Spinifex Admin CLI](/docs/spinifex-admin-cli)) -- AWS CLI configured with the account's profile: +- AWS CLI configured with your account's profile. The default `spinifex` account created at cluster setup works out of the box; to work in a separate account, create one with `spx admin account create` (see [Spinifex Admin CLI](/docs/spinifex-admin-cli)): ```bash -export AWS_PROFILE=spinifex-myteam +export AWS_PROFILE=spinifex ``` ## Instructions @@ -327,34 +325,6 @@ aws iam detach-role-policy --role-name app-server \ aws iam delete-role --role-name app-server ``` -## Command Reference - -| Command | Key Parameters | Notes | -| ------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------ | -| `create-role` | `--role-name`, `--assume-role-policy-document`, `--path`, `--description`, `--max-session-duration`, `--tags` | Trust policy required | -| `get-role` | `--role-name` | | -| `list-roles` | `--path-prefix` | | -| `update-role` | `--role-name`, `--description`, `--max-session-duration` | | -| `update-assume-role-policy` | `--role-name`, `--policy-document` | Replaces the trust policy | -| `delete-role` | `--role-name` | Must have no policies or profiles | -| `attach-role-policy` / `detach-role-policy` | `--role-name`, `--policy-arn` | | -| `list-attached-role-policies` | `--role-name` | | -| `put-role-policy` | `--role-name`, `--policy-name`, `--policy-document` | Inline policy | -| `get-role-policy` / `delete-role-policy` | `--role-name`, `--policy-name` | | -| `list-role-policies` | `--role-name` | Inline policy names | -| `tag-role` / `untag-role` / `list-role-tags` | `--role-name`, `--tags`/`--tag-keys` | | -| `create-instance-profile` | `--instance-profile-name`, `--path`, `--tags` | | -| `get-instance-profile` | `--instance-profile-name` | Includes bound role | -| `list-instance-profiles` | `--path-prefix` | | -| `list-instance-profiles-for-role` | `--role-name` | | -| `add-role-to-instance-profile` | `--instance-profile-name`, `--role-name` | Max 1 role per profile | -| `remove-role-from-instance-profile` | `--instance-profile-name`, `--role-name` | | -| `delete-instance-profile` | `--instance-profile-name` | Must contain no role | -| `associate-iam-instance-profile` | `--instance-id`, `--iam-instance-profile` | Works on running instances | -| `disassociate-iam-instance-profile` | `--association-id` | | -| `replace-iam-instance-profile-association` | `--association-id`, `--iam-instance-profile` | Returns a new association ID | -| `describe-iam-instance-profile-associations`| `--association-ids`, `--filters` (instance-id, state) | | - ## Troubleshooting ### MalformedPolicyDocument When Creating a Role diff --git a/docs/identity/iam-users-and-policies/README.md b/docs/identity/iam-users-and-policies/README.md index b43c29baf..4619c8da0 100644 --- a/docs/identity/iam-users-and-policies/README.md +++ b/docs/identity/iam-users-and-policies/README.md @@ -30,14 +30,13 @@ resources: - [Policies](#policies) - [Attaching Policies](#attaching-policies) - [Putting It All Together](#putting-it-all-together) -- [Command Reference](#command-reference) - [Troubleshooting](#troubleshooting) --- ## Overview -Spinifex implements AWS-compatible IAM covering user management, access key lifecycle, policy CRUD, and policy attachment. Inline user policies (`put-user-policy`), user and policy tagging, and IAM roles for EC2 instances (see [IMDS](/docs/imds)) are also supported. All IAM resources are scoped to the account that creates them — users in one account cannot see or modify resources in another. +Spinifex implements AWS-compatible IAM covering user management, access key lifecycle, policy CRUD, and policy attachment. Inline user policies (`put-user-policy`), user and policy tagging, [groups](/docs/iam-groups), and [roles and instance profiles](/docs/iam-roles-and-instance-profiles) are also supported. All IAM resources are scoped to the account that creates them — users in one account cannot see or modify resources in another. When you create an account with `spx admin account create`, Spinifex bootstraps a root user with an `AdministratorAccess` policy and writes the credentials to `~/.aws/credentials`. From there, you use the standard AWS CLI to manage additional users and permissions. @@ -46,11 +45,10 @@ When you create an account with `spx admin account create`, Spinifex bootstraps ## Prerequisites - A running Spinifex cluster with the AWS gateway started -- An account created via `spx admin account create` (see [Spinifex Admin CLI](/docs/spinifex-admin-cli)) -- AWS CLI configured with the account's profile: +- AWS CLI configured with your account's profile. The default `spinifex` account created at cluster setup works out of the box; to work in a separate account, create one with `spx admin account create` (see [Spinifex Admin CLI](/docs/spinifex-admin-cli)): ```bash -export AWS_PROFILE=spinifex-myteam +export AWS_PROFILE=spinifex ``` ## Instructions @@ -459,36 +457,14 @@ AWS_PROFILE=spinifex-carol aws ec2 terminate-instances --instance-ids i-123 # ^ This will be denied by the NoTerminate statement ``` -## Command Reference - -| Command | Key Parameters | Notes | -| ----------------------------- | -------------------------------------------- | --------------------------------- | -| `create-user` | `--user-name`, `--path` | Path default: `/` | -| `get-user` | `--user-name` | | -| `list-users` | `--path-prefix` | | -| `delete-user` | `--user-name` | Must have no keys or policies | -| `create-access-key` | `--user-name` | Max 2 per user; secret shown once | -| `list-access-keys` | `--user-name` | | -| `delete-access-key` | `--user-name`, `--access-key-id` | | -| `update-access-key` | `--user-name`, `--access-key-id`, `--status` | `Active` or `Inactive` | -| `create-policy` | `--policy-name`, `--policy-document` | Max 6144 bytes | -| `get-policy` | `--policy-arn` | Metadata only | -| `get-policy-version` | `--policy-arn`, `--version-id` | Use `v1`; includes document | -| `list-policy-versions` | `--policy-arn` | | -| `list-policies` | | | -| `delete-policy` | `--policy-arn` | Must not be attached | -| `attach-user-policy` | `--user-name`, `--policy-arn` | Idempotent | -| `detach-user-policy` | `--user-name`, `--policy-arn` | | -| `list-attached-user-policies` | `--user-name` | | - ## Troubleshooting ### AccessDenied on IAM Commands -The calling user must have IAM permissions. Attach a policy with `iam:*` actions, or use the root account profile: +The calling user must have IAM permissions. Attach a policy with `iam:*` actions, or use the account's admin profile: ```bash -export AWS_PROFILE=spinifex-myteam +export AWS_PROFILE=spinifex aws iam list-users ``` @@ -511,7 +487,7 @@ If the key was deleted, create a new one. ### DeleteConflict When Deleting a User -The user still has access keys or attached policies. Remove them first: +The user still has access keys, attached policies, or [group memberships](/docs/iam-groups). Remove them first: ```bash # Check for access keys @@ -519,6 +495,9 @@ aws iam list-access-keys --user-name alice # Check for attached policies aws iam list-attached-user-policies --user-name alice + +# Check for group memberships +aws iam list-groups-for-user --user-name alice ``` ### DeleteConflict When Deleting a Policy