This project can be used to create new AWS IAM Identity Center (SSO) Permission Sets. The Terraform
code in this repository uses AWS Secrets Manager to store key-value pairs that help us map AWS Managed IAM Policies to new Permission Sets, as well as assigning them to accounts, and granting groups access through IAM Identity Center.
While this sounds relatively straightforward, there is a lot to be desired with AWS SSO, so I hope that this simplifies the process for you!
This project was created as a complement to blog content written for https://shadetree.dev
Managing SSO permissions in AWS can be...tedious to say the least. Hopefully using Terraform
will make at least the provisioning process easier so that you can add or modify them more scalably!
By providing the values we'll need in secrets
, they can be kept up independent of Terraform
code, and we are not storing any sensitive details like lots of users, groups, and accounts. The examples in this project use generic role-based access control (RBAC) by using five (5) persona roles:
SecurityAuditors
- a role that will have theSecurityAudit
managed policy attachedDBAdmins
- a role that will be grantedAmazonDynamoDBFullAccess
andAmazonRDSFullAccess
FinanceBeanCounters
- a role that will be granted the job role (edge case syntax, more on that)Billing
ManagersWhoWontLogInAnyway
- a role that is grantedReadOnlyAccess
DevOpsAdmins
- a role that gets theAdministratorAccess
managed policy
This is not intended to be wholly useful in its construction, but is a bit of a tongue-in-cheek example of some typical enterprise roles.
This project assumes that you are using a remote s3 backend
state. You will need to update the bucket
, dynamodb_table
, and region
accordingly. If you use another backend
type, or if you intend to just use local
then you can comment out the provided configuration.
This project assumes that you are using AWS Secrets Manager secrets
to store key configuration data. This is a generic example, constructed from the premise of this blog post. Here's the TL;DR:
- Ensure that you have access to the AWS account where you will be deploying these resources. You should ideally use a delegated administrator account for a few key reasons:
- ANY Permission Set you create from the AWS Organizations management account cannot be modified later, anywhere but in management account. You would otherwise have to destroy and recreate these permission sets to manage them in a delegated account.
NOTE: You actually cannot assign anyone permission TO your management account from outside if it, no matter what. So if you have need for that through
Terraform
, you should add aproviders.tf
entry for that account and use it accordingly - You should keep any and all functions out of the management account that you possibly can! This is a known best practice, and delegating access to a separate account makes it easier for Role-based Access Control, maybe via SSO roles even ;)
- ANY Permission Set you create from the AWS Organizations management account cannot be modified later, anywhere but in management account. You would otherwise have to destroy and recreate these permission sets to manage them in a delegated account.
NOTE: You actually cannot assign anyone permission TO your management account from outside if it, no matter what. So if you have need for that through
- IAM Identity Center should be set up already and have groups / users we will be managing.
- Set up three (3) secrets, where the
key
will always be the name you want to give your Permission Sets. I recommend storing them in paths like:-
/aws/org/sso/managed-policies
for the mapping ofPermissionSetName
toAWS Managed IAM Policies
by names (we do the ARN construction in the code) -
/aws/org/sso/account-mapping
for the mapping ofPermissionSetName
to a comma-separated list of account IDs -
/aws/org/sso/group-mapping
for the mapping ofPermissionSetName
to IAM Identity Center group names (we do the ID lookups in the code)For users you can do something similar, and should be able to follow the same logic in the
locals.tf
of themodules/permission-set
-
You can find an example of this setup in this blog post, which is the inspiration for this code!
-
/aws/org/sso/account-mapping
In my example I am using two (2) accounts, because this is a demo environment. This code should work for any number
n
accounts bym
groups thanks to the witchcraft oflocals.tf
hackery that goes on!
- Make sure you have installed the Terraform cli If you are a MacOS user, this can be accomplished via Homebrew:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
- Configure your
providers
as needed, either using the SSO profile viaprofile = "your-profile-name"
or by assuming a role with theassume_role {}
block.
provider "aws" {
region = var.region
# for local use, if you can assume the role specified no changes required
# otherwise, you can use your local SSO profile by commenting OUT assume_role
# and commenting in your profile
profile = "automation"
# assume_role {
# role_arn = "arn:aws:iam::${var.account_id}:role/OrganizationAccountAccessRole"
# }
}
NOTE: The OrganizationAccountAccessRole
is a default role created by AWS. You will need to have a trust policy allowing access to assume it if you use this, otherwise replace it with a valid role in the account
- Make sure that you provide the mandatory parameters for this project to deploy. If running this locally, you can
export
the values as environment variables like so:
export TF_VAR_account_id="your-delegated-sso-admin-account"
export TF_VAR_name="workspace-name"
export TF_VAR_region="your-aws-region"
In this project, TF_VAR_name
is not really used other than setting the workspace
but I keep these variables consistent across all my projects, so keep up the habit and you'll be able to use many of these :)
This project includes a Makefile
that will run your terraform <command>
functions accordingly, and automatically sets up a Terraform Workspace. If you do use a remote backend, you can set the workspace_key_prefix
in backend.tf
to whatever you want the parent "folder" to be for this.
If you have exported the proper variables as described in the above Setup section, then you should be able to run your commands!
make init
# OUTPUT
make plan
# OUTPUT
make apply
If you prefer to run the commands yourself, you can simply follow the typical terraform init
and terraform plan/apply
stages, but I find the Makefile
streamlines things and this is a common pattern for managing Terraform
.
You should see output similar to this if you succeeded:
make init ✭ ✱
Formatting Terraform files...
Initializing Terraform...
terraform init -reconfigure
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing modules...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v5.35.0
Terraform has been successfully initialized!
make plan
# bunch of output about your resources
.
.
.
Plan: 19 to add, 0 to change, 0 to destroy.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "tfplan"
make apply
# bunch of output with too many unique IDs I am too lazy to mask, so they are ommitted
.
.
.
Apply complete! Resources: 19 added, 0 changed, 0 destroyed.
If you want to destroy your resources, you can do so by running make destroy
, which will prompt you for approval.
make destroy
.
.
.
Plan: 0 to add, 0 to change, 19 to destroy.
Do you really want to destroy all resources in workspace "sso-demo"?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
.
.
.
Destroy complete! Resources: 19 destroyed.
If you want to make sure it actually works, you can add your user to several groups. Here I have added myself to all of the groups for this project, but not yet run the code:
As you can see, I just have two (2) accounts with my lazy AdministratorAccess
SSO role. Then, after running applying the Terraform
code from this project:
As soon as it is done applying, if you refresh the SSO UI, you can see three (3) accounts that I now have access to, as well as a bunch of new roles assigned to the matching accounts!
You should just as quickly be able to destroy
and refresh to see them gone again. Neat, eh? :)
This information was generated using terraform-docs. You can install this per the instructions provided in its respective project repository, and then generate a table like below using:
terraform-docs markdown table . | pbcopy
(the pbcopy
command is specific to MacOS and used to copy to clipboard; your command may vary)
Name | Version |
---|---|
terraform | >= 1.5.0 |
aws | >= 5.20 |
Name | Version |
---|---|
aws | 5.35.0 |
Name | Source | Version |
---|---|---|
permission-set | ./modules/permission-set | n/a |
Name | Type |
---|---|
aws_secretsmanager_secret.accounts | data source |
aws_secretsmanager_secret.groups | data source |
aws_secretsmanager_secret.policies | data source |
aws_secretsmanager_secret_version.accounts | data source |
aws_secretsmanager_secret_version.groups | data source |
aws_secretsmanager_secret_version.policies | data source |
aws_ssoadmin_instances.sso | data source |
Name | Description | Type | Default | Required |
---|---|---|---|---|
account_id | The 12 digit AWS account ID to deploy resources to | string |
"" |
no |
name | The name you want to give to resources created | string |
"" |
no |
region | The AWS region where resources should be deployed | string |
"us-west-2" |
no |
sso_enabled | Flag for whether or not to look up SSO role for bucket and key access | bool |
true |
no |
No outputs.