lightweight, self-service AWS IAM management

Contents

Overview

goliath grouper

"It's kind of a big deal..."

Key tenets:

  • You hire smart people you can trust
  • Self-service enables autonomy
  • Elimination of toil frees humans for more creative work

With that in mind, if you're a member of an autonomous agile team and have AWS access required to do your job, one conclusion is that you should be able to grant team members the same access without friction. Grouper lets you do that.

TODO: link to blog

Architecture

Preferred deployment scenario, following the best practice of sandboxing services in dedicated accounts and using cross-account role assumption.

grouper architecture

Prerequisites

While all are not specific to grouper or strictly required, keep the following in mind when deploying grouper:

Security controls

Grouper is meant to be as lightweight as possible. One decision to accomplish that is allowing RO endpoints (e.g. get a list of groups) to be accessed without authentication. While RW endpoints (e.g. updating a group) do require authentication and authorization, there is likely no reason for this service to ever be exposed to the Internet.

Whether you lock it down using security groups, authenticated proxies, internal ALBs or other means is up to you. Just place it in a trust zone with adequate protections considering the role it plays.

I've deployed it on a private VPC, behind an internal ALB, with a security group only allowing access from VPN. You don't have to be that paranoid, but it doesn't hurt!

AWS CLI

You need to have the AWS CLI installed and configured. The groupadd script wraps aws-vault vs using the AWS CLI directly, but you still need a functional CLI to initially load credentials. AWS has excellent stand-alone installers and most OS distributions have packaged options (AUR, homebrew, etc). If you haven't done this before, be sure to install v2!

aws-vault

If you routinely juggle a lot of different accounts and don't like having plaintext credentials lying around your disk (although I'm sure you have disk encryption enabled, so this is just about layers of protection at this point!), you need aws-vault.

Technically you don't need the AWS CLI or aws-vault installed. You can simply curl the API! These are requirements of the groupadd convenience wrapper. That said, if you're doing other things which routinely use the AWS CLI, you should be using aws-vault!

curl and jq

While not a requirement for the API, curl and jq are used by the groupadd script. Who doesn't have these installed anyway? :-)

Workflow

This is a lean microservice meant to accomplish one thing: Self-service AWS IAM management for teams. IAM is a big beast, so more specifically: Help individuals with AWS access navigate a group-based permissions scheme, and enable group members to self-serve adding new members.

Based on that, we need discovery as well as management of group members. The following scenarios are the most common I've seen...

What groups exist?

I wish all groups neatly conformed to the naming convention (because naming conventions solve everything!), but organic growth is a reality. This can be solved with good documentation... but documentation can be generated from good tooling (and anyone who grew up in the "API generation" can simply poke around and avoid managing more documentation).

http https://grouper/groups
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 581
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Oct 2021 20:56:40 GMT

{
  "message": {
    "groups": [
      {
        "Arn": "arn:aws:iam::012345678901:group/foo",
        "CreateDate": "2019-08-20T18:48:41Z",
        "GroupId": "AGPAWSFUDZ6256EXAMPLE",
        "GroupName": "foo",
        "Path": "/"
      },
      {
        "Arn": "arn:aws:iam::012345678901:group/bar",
        "CreateDate": "2019-08-20T18:48:41Z",
        "GroupId": "AGPAWSFUDZ622BEXAMPLE",
        "GroupName": "bar",
        "Path": "/"
      },
...

Who do I ask for access?

You've been pulled into a new team and even found a matching group, but aren't completely sure who to ask for access. You could ping your manager, but they're always in meetings. You could @team but you're really looking for @subteam. Lookup the group members yourself and start a slack thread with those who can directly help you!

http https://grouper/groups/foo
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sun, 16 Jan 2022 23:11:24 GMT
Transfer-Encoding: chunked

{
    "message": {
        "group": {
            "Arn": "arn:aws:iam::012345678901:group/foo",
            "CreateDate": "2016-08-22T13:02:49Z",
            "GroupId": "AGPAJGUTBU62VREXAMPLE",
            "GroupName": "foo",
            "Path": "/"
        },
        "members": [
            {
                "Arn": "arn:aws:iam::012345678901:user/some.user",
                "CreateDate": "2018-06-04T21:49:03Z",
                "PasswordLastUsed": "2022-01-14T16:40:57Z",
                "Path": "/",
                "PermissionsBoundary": null,
                "Tags": null,
                "UserId": "AIDAIDYYHCWNMGEXAMPLE",
                "UserName": "some.user"
            },
            {
                "Arn": "arn:aws:iam::012345678901:user/another.user",
                "CreateDate": "2016-11-15T15:49:50Z",
                "PasswordLastUsed": "2022-01-14T15:30:32Z",
                "Path": "/",
                "PermissionsBoundary": null,
                "Tags": null,
                "UserId": "AIDAIHXNI2F3E5EXAMPLE",
                "UserName": "another.user"
            },
...

What groups am I in?

Some times it's not obvious what groups you belong to... you can get a list of non-sensitive user information, including a list of all assigned groups:

http https://grouper/users/some.user
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 581
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Oct 2021 20:56:40 GMT

{
    "message": {
        "groups": [
            {
                "Arn": "arn:aws:iam::012345678901:group/foo",
                "CreateDate": "2016-09-12T19:05:59Z",
                "GroupId": "AGPAI5QY6GU5PAEXAMPLE",
                "GroupName": "foo",
                "Path": "/"
            },
            {
                "Arn": "arn:aws:iam::012345678901:group/bar",
                "CreateDate": "2016-08-22T13:02:49Z",
                "GroupId": "AGPAJGUTBU62VZEXAMPLE",
                "GroupName": "bar",
                "Path": "/"
            }
        ],
        "user": {
            "Arn": "arn:aws:iam::012345678901:user/some.user",
            "CreateDate": "2020-01-08T21:06:25Z",
            "PasswordLastUsed": "2021-10-30T20:28:31Z",
            "Path": "/",
            "PermissionsBoundary": null,
            "Tags": null,
            "UserId": "AIDAWSFUDZ626PEXAMPLE",
            "UserName": "some.user"
        }
    },
    "status": 200
}

How do I add group members?

You can only manage groups you are a member of (members of the privileged ADMIN_GROUP can manage all groups). If you need new groups created, custom policies attached, added to groups team members are not currently part of, group members removed, etc. start with a conversation. If it's a common enough use case, submit a PR. :-)

To add new team members to one of your groups, use the groupadd helper. This is only a convenience wrapper, you could just curl the API or use/build other options. Endpoints are documented in Implementation Detail.

./groupadd

USAGE: groupadd -g <IAM_GROUP> -m <IAM_USERNAME> [-c <CALLER_ID> -k <KEY_ID>]

  -g  Friendly name of IAM group to update
  -m  IAM username of group member to add
  -c  User ARN of requester (only needed if auto-detection fails)
  -k  AWS_ACCESS_KEY_ID of requestor (only needed if auto-detection fails)

You only need -g and -m, by default the other arguments are auto-detected (requires properly configured AWS CLI and aws-vault):

./groupadd -g testgroup -m some.user
{
  "message": {
    "groups": [
      {
        "Arn": "arn:aws:iam::012345678901:group/foo",
        "CreateDate": "2016-09-12T19:05:59Z",
        "GroupId": "AGPAI5QY6GU5PAEXAMPLE",
        "GroupName": "foo",
        "Path": "/"
      },
      {
        "Arn": "arn:aws:iam::012345678901:group/bar",
        "CreateDate": "2016-08-22T13:02:49Z",
        "GroupId": "AGPAJGUTBU62VZEXAMPLE",
        "GroupName": "bar",
        "Path": "/"
      },
      {
        "Arn": "arn:aws:iam::012345678901:group/testgroup",
        "CreateDate": "2021-10-26T18:30:38Z",
        "GroupId": "AGPAWSFUDZ62ZSEXAMPLE",
        "GroupName": "testgroup",
        "Path": "/"
      }
    ],
    "user": {
      "Arn": "arn:aws:iam::012345678901:user/some.user",
      "CreateDate": "2020-01-08T21:06:25Z",
      "Path": "/",
      "UserId": "AIDAWSFUDZ626PEXAMPLE",
      "UserName": "some.user",
      "PasswordLastUsed": "2021-10-30T20:28:31Z",
      "PermissionsBoundary": null,
      "Tags": null
    }
  },
  "status": 201
}

How Auto-Detection Works

The groupadd helper script attempts to auto-detect AWS caller ID and access key ID to construct the API payload. This requires properly configured AWS CLI and aws-vault.

For AWS CLI, you must have ~/.aws/config and ~/.aws/credentials with entries for your main IAM account (see architecture diagram):

cat ~/.aws/config
[profile main]
aws_account_id=your-iam-account
output=json
region=your-default-region
mfa_serial=arn:aws:iam::012345678901:mfa/first.lastcat ~/.aws/credentials
[main]
aws_access_key_id = ...
aws_secret_access_key = ...

aws-vault should have these credentials added:

aws-vault list
Profile                  Credentials              Sessions
=======                  ===========              ========
main                     main                     sts.GetSessionToken:5h6m32s

Then groupadd can use these for auto-detection:

grep PROFILE groupadd
PROFILE=${AWS_PROFILE:-main}
VAULT="aws-vault exec $PROFILE --"

If you have a name other than main for your IAM account, simply override AWS_PROFILE when running groupadd:

AWS_PROFILE=foobarbaz ./groupadd -g testgroup -m some.user

FAQ

Q: credentials missing errors running groupadd

A: Check aws-vault list to see if the credentials for AWS_PROFILE (main by default) are loaded. If not, try aws-vault add <profile_name>. If you change profile names or credential configuration, you need to aws-vault remove/add.

Q: Unable to parse config file: ~/.aws/credentials

A: Make sure you setup ~/.aws/credentials using aws configure.

Q: InvalidClientTokenId or The security token included in the request is invalid. Manually running aws iam list-access-keys also fails.

A: Ensure the default policy attached to users allows listing access keys. If that is true, this is typically a configuration issue.

You don't have to follow this exactly, but here are two example configurations known to work. First, using default and sourcing that as needed:

[default]
output=json
region=your-default-region
mfa_serial=arn:aws:iam::012345678901:mfa/first.last

[profile main]
role_arn=arn:aws:iam::012345678901:role/admin
source_profile=default
mfa_serial=arn:aws:iam::012345678901:mfa/first.last

Defining the main profile directly (main is the default used by groupadd):

[profile main]
aws_account_id=your-iam-account
output=json
region=your-default-region
mfa_serial=arn:aws:iam::012345678901:mfa/first.last

Important things to remember:

  • You need to specify mfa_serial for each profile (not just the sourced profile).
  • You need matching ~/.aws/credentials entries
  • Plain-text credentials can be removed once you aws-vault add ...

TODO

  • Add tests
  • Fully encapsulate all build steps (more Makefile steps inside Dockerfile)
  • Update Terraform to include all IAM bits
Owner
Mike Hoskins
Think, do, learn, repeat.
Mike Hoskins
Similar Resources

Apis para la administracion de notifiaciones, utilizando servicios como AWS SNS y AWS SQS

notificacion_api Servicio para envío de notificaciónes por difusión en AWS SNS Especificaciones Técnicas Tecnologías Implementadas y Versiones Golang

Jan 7, 2022

Simple CRUD API written in Go, built using AWS SAM tool and using the AWS' infrastructure.

Simple CRUD API written in Go, built using AWS SAM tool and using the AWS' infrastructure.

tutor-pet API Simple CRUD API written in Go, built using AWS SAM tool and using the AWS' infrastructure. Macro architecture: Code architecture: Pre-Re

Aug 17, 2022

Aws-parameter-bulk - Export AWS SSM Parameter Store values in bulk to .env files

aws-parameter-bulk Utility to read parameters from AWS Systems Manager (SSM) Par

Oct 18, 2022

Aws-cognito-demo-go - Source code for AWS Cognito in Go

AWS Cognito Demo in Go Source code for YouTube series, AWS Cognito in Go - https

Dec 10, 2022

Una prueba técnica: Servicio Golang REST API local, sobre Docker, gRPC, AWS Serverless y sobre Kubernetes en AWS EC2

Una prueba técnica: Servicio Golang REST API local, sobre Docker, gRPC, AWS Serverless y sobre Kubernetes en AWS EC2

May 7, 2022

Aws-cdk-go-examples - Example projects using the AWS CDK by Golang

aws-cdk-go-examples Example projects using the AWS CDK by Golang Useful commands

Nov 24, 2022

A simple self-hostable Machine Translation service, powered by spaGO

A simple self-hostable Machine Translation service, powered by spaGO

Nov 9, 2022

Self-service account creation and credential reset for FreeIPA

Self-service account creation and credential reset for FreeIPA

Auri Auri stands for: Automated User Registration IPA Auri implements self service account creation and reset of credentials for FreeIPA Features Requ

Dec 21, 2022

Qfy - Self-hosted implementation of Synthetics - Monitoring checks to validate your service availability

qfy Self-hosted implementation of Synthetics - Monitoring checks to validate you

Feb 23, 2022
Feb 7, 2022
Assume AWS IAM roles from GitHub Actions workflows with no stored secrets
Assume AWS IAM roles from GitHub Actions workflows with no stored secrets

AWS IAM roles for GitHub Actions workflows Background and rationale GitHub Actions are a pretty nice solution for CI/CD. Where they fall short is inte

Feb 12, 2022
Automatically roll your AWS IAM access key (aws_access_key_id) and secret key (aws_secret_access_key).

roll-it Keep your AWS Credentials fresh ?? on Windows, Mac, Linux (arm or x86)! What it Does Programmatically rotate your AWS IAM access keys and secr

Jan 6, 2023
A package for access aws service using AWS SDK for Golang

goaws ?? A package for access aws service using AWS SDK for Golang Advantage with goaws package Example for get user list IAM with AWS SDK for Golang

Nov 25, 2021
Zms - The Bhojpur ZMS is a software-as-a-service product applied in different risk management areas. It is a containment Zone Management System based on Bhojpur.NET Platform.

Bhojpur ZMS - Zone Management System The Bhojpur ZMS is a software-as-a-service product used as a Zone Management System based on Bhojpur.NET Platform

Sep 26, 2022
A Pulumi multi language component to create an IAM role for an EKS cluster

xyz Pulumi Component Provider (Go) This repo is a boilerplate showing how to create a Pulumi component provider written in Go. You can search-replace

Oct 27, 2021
No need for IAM users when we have Yubikeys

cloudkey As far as I can tell, the only justification for AWS IAM users that I hear nowadays is for usage on non-interactive systems outside of AWS, e

Dec 5, 2022
Send IAM-signed requests to AppSync and API Gateway

golang-iam-requests Provides helpers to send IAM-signed requests to AWS AppSync and AWS API Gateway services Generates a v4 sign using IAM credentials

Apr 21, 2022
Simple no frills AWS S3 Golang Library using REST with V4 Signing (without AWS Go SDK)

simples3 : Simple no frills AWS S3 Library using REST with V4 Signing Overview SimpleS3 is a golang library for uploading and deleting objects on S3 b

Nov 4, 2022
Integrate AWS EKS Anywhere cluster with AWS Services
 Integrate AWS EKS Anywhere cluster with AWS Services

This article provides step-by-step instruction on integrating AWS EKS Anywhere with AWS Services so the applications running on customer data center can securely connect with these services.

Mar 6, 2022