A best-practices set of IAM roles for cross-account access
This module can be used to allow IAM users from other AWS accounts to access your AWS accounts (i.e. cross-account access). This allows you to define each environment (mgmt, stage, prod, etc) in a separate AWS account, your IAM users in a single account, and to allow those users to easily switch between accounts with a single set of credentials.
If you're not familiar with IAM concepts, start with the Background Information section as a way to familiarize yourself with the terminology.
Resources Created
This module creates the following IAM roles (all optional):
IAM Roles intended for human users
These IAM Roles are intended to be assumed by human users (i.e., IAM Users in another AWS account). The default
maximum session expiration for these roles is 12 hours (configurable via the var.max_session_duration_human_users
).
Note that these are the maximum session expirations; the actual value for session expiration is specified when
making API calls to assume the IAM role (see aws-auth).
-
allow-read-only-access-from-other-accounts: Users from the accounts in
var.allow_read_only_access_from_other_account_arns
will get read-only access to all services in this account. -
allow-billing-access-from-other-accounts: Users from the accounts in
var.allow_billing_access_from_other_account_arns
will get full (read and write) access to the billing details for this account. -
allow-support-access-from-other-accounts: Users from the accounts in
var.allow_support_access_from_other_account_arns
will get access to AWS support for this account. -
allow-logs-access-from-other-accounts: Users from the accounts in
var.allow_logs_access_from_other_account_arns
will get read access to the logs in CloudTrail, AWS Config, and CloudWatch in this account. Since CloudTrail logs may be encrypted with a KMS CMK, ifvar.cloudtrail_kms_key_arn
is set, these users will also get permissions to decrypt using this KMS CMK. -
allow-dev-access-from-other-accounts: Users from the accounts in
var.allow_dev_access_from_other_account_arns
will get full (read and write) access to the services in this account specified invar.dev_permitted_services
. -
allow-full-access-from-other-accounts: Users from the accounts in
var.allow_full_access_from_other_account_arns
will get full (read and write) access to all services in this account. -
allow-iam-admin-access-from-other-accounts: Users from the accounts in
var.allow_iam_admin_access_from_other_account_arns
will get IAM admin access.
IAM Roles intended for machine users
These IAM Roles are intended to be assumed by machine users (i.e., an EC2 Instance in another AWS account). The default
maximum session expiration for these roles is 1 hour (configurable via the var.max_session_duration_machine_users
).
Note that these are the maximum session expirations; the actual value for session expiration is specified when
making API calls to assume the IAM role (see aws-auth).
-
allow-ssh-grunt-access-from-other-accounts: Users (or more likely, EC2 Instances) from the accounts in
var.allow_ssh_grunt_access_from_other_account_arns
will get read access to IAM Groups and public SSH keys. This is useful to allow ssh-grunt running on EC2 Instances in other AWS accounts to validate SSH connections against IAM users defined in this AWS account. -
allow-auto-deploy-access-from-other-accounts: Users from the accounts in
var.allow_auto_deploy_from_other_account_arns
will get automated deployment access to all services in this account with the permissions specified invar.auto_deploy_permissions
. The main use case is to allow a CI server (e.g. Jenkins) in another AWS account to do automated deployments in this AWS account.
How to switch between accounts
Switching in the AWS console
Check out the AWS Switching to a Role (AWS Console) documentation.
Note that this module automatically outputs the convenient sign-in URLs to quickly switch to a given role. The outputs
are named allow_XXX_access_sign_in_url
, where XXX
is one of read-only
, billing
, dev
, or full
.
Switching with CLI tools (including Terraform)
Check out the AWS Switching to a Role (AWS Command Line Interface) documentation. Note that assuming roles with the AWS CLI takes quite a few steps, so use the aws-auth script to reduce it to a one-liner.
Background Information
For background information on IAM, IAM users, IAM policies, and more, check out the background information docs in the iam-policies module.
Sample Usage
- Terraform
- Terragrunt
# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S CROSS-ACCOUNT-IAM-ROLES MODULE
# ------------------------------------------------------------------------------------------------------
module "cross_account_iam_roles" {
source = "git::git@github.com:gruntwork-io/terraform-aws-security.git//modules/cross-account-iam-roles?ref=v0.74.5"
# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------
# The ID of the AWS Account.
aws_account_id = <string>
# Should we require that all IAM Users use Multi-Factor Authentication for
# both AWS API calls and the AWS Web Console? (true or false)
should_require_mfa = <bool>
# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------
# Allow GitHub Actions to assume the auto deploy IAM role using an OpenID
# Connect Provider. Refer to the docs for github-actions-iam-role for more
# information. Note that this is mutually exclusive with
# var.allow_auto_deploy_from_other_account_arns.
allow_auto_deploy_from_github_actions = null
# A list of IAM ARNs from other AWS accounts that will be allowed to assume
# the auto deploy IAM role that has the permissions in
# var.auto_deploy_permissions.
allow_auto_deploy_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_auto_deploy_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to the billing info for this account.
allow_billing_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_billing_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to the services in this account specified in
# var.dev_permitted_services.
allow_dev_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_dev_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to this account.
allow_full_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_full_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed IAM admin
# access to this account.
allow_iam_admin_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed read access
# to the logs in CloudTrail, AWS Config, and CloudWatch for this account. If
# var.cloudtrail_kms_key_arn is set, will also grant decrypt permissions for
# the KMS CMK.
allow_logs_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed read-only
# access to this account.
allow_read_only_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_read_only_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed read access
# to IAM groups and publish SSH keys. This is used for ssh-grunt.
allow_ssh_grunt_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed access to
# AWS support for this account.
allow_support_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_support_access_iam_role_permissions_boundary = null
# What to name the auto deploy IAM role
auto_deploy_access_iam_role_name = "allow-auto-deploy-from-other-accounts"
# A list of IAM permissions (e.g. ec2:*) which will be granted for automated
# deployment.
auto_deploy_permissions = []
# What to name the billing access IAM role
billing_access_iam_role_name = "allow-billing-only-access-from-other-accounts"
# The ARN of a KMS CMK used to encrypt CloudTrail logs. If set, the logs IAM
# role will include permissions to decrypt using this CMK.
cloudtrail_kms_key_arn = null
# Set to false to have this module create no resources. This weird parameter
# exists solely because Terraform does not support conditional modules.
# Therefore, this is a hack to allow you to conditionally decide if the
# resources should be created or not.
create_resources = true
# What to name the dev access IAM role
dev_access_iam_role_name = "allow-dev-access-from-other-accounts"
# A list of AWS services for which the developers from the accounts in
# var.allow_dev_access_from_other_account_arns will receive full permissions.
# See
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_actions-resources-contextkeys.html
# to find the service name. For example, to grant developers access only to
# EC2 and Amazon Machine Learning, use the value ["ec2","machinelearning"]. Do
# NOT add iam to the list of services, or that will grant Developers de facto
# admin access.
dev_permitted_services = []
# What to name the full access IAM role
full_access_iam_role_name = "allow-full-access-from-other-accounts"
# What to name the IAM admin access IAM role
iam_admin_access_iam_role_name = "allow-iam-admin-access-from-other-accounts"
# Include this value as a prefix in the name of every IAM role created by this
# module. This is useful to prepend, for example, '<account-name>-' to every
# IAM role name: e.g., allow-full-access-from-other-accounts becomes
# stage-allow-full-access-from-other-accounts.
iam_role_name_prefix = ""
# What to name the logs access IAM role
logs_access_iam_role_name = "allow-logs-access-from-other-accounts"
# The maximum allowable session duration, in seconds, for the credentials you
# get when assuming the IAM roles created by this module. This variable
# applies to all IAM roles created by this module that are intended for people
# to use, such as allow-read-only-access-from-other-accounts. For IAM roles
# that are intended for machine users, such as
# allow-auto-deploy-from-other-accounts, see
# var.max_session_duration_machine_users.
max_session_duration_human_users = 43200
# The maximum allowable session duration, in seconds, for the credentials you
# get when assuming the IAM roles created by this module. This variable
# applies to all IAM roles created by this module that are intended for
# machine users, such as allow-auto-deploy-from-other-accounts. For IAM roles
# that are intended for human users, such as
# allow-read-only-access-from-other-accounts, see
# var.max_session_duration_human_users.
max_session_duration_machine_users = 3600
# What to name the read-only access IAM role
read_only_access_iam_role_name = "allow-read-only-access-from-other-accounts"
# What to name the ssh-grunt access IAM role
ssh_grunt_access_iam_role_name = "allow-ssh-grunt-access-from-other-accounts"
# What to name the support access IAM role
support_access_iam_role_name = "allow-support-access-from-other-accounts"
# A map of tags to apply to the IAM roles.
tags = {}
# When true, all IAM policies will be managed as dedicated policies rather
# than inline policies attached to the IAM roles. Dedicated managed policies
# are friendlier to automated policy checkers, which may scan a single
# resource for findings. As such, it is important to avoid inline policies
# when targeting compliance with various security standards.
use_managed_iam_policies = true
}
# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S CROSS-ACCOUNT-IAM-ROLES MODULE
# ------------------------------------------------------------------------------------------------------
terraform {
source = "git::git@github.com:gruntwork-io/terraform-aws-security.git//modules/cross-account-iam-roles?ref=v0.74.5"
}
inputs = {
# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------
# The ID of the AWS Account.
aws_account_id = <string>
# Should we require that all IAM Users use Multi-Factor Authentication for
# both AWS API calls and the AWS Web Console? (true or false)
should_require_mfa = <bool>
# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------
# Allow GitHub Actions to assume the auto deploy IAM role using an OpenID
# Connect Provider. Refer to the docs for github-actions-iam-role for more
# information. Note that this is mutually exclusive with
# var.allow_auto_deploy_from_other_account_arns.
allow_auto_deploy_from_github_actions = null
# A list of IAM ARNs from other AWS accounts that will be allowed to assume
# the auto deploy IAM role that has the permissions in
# var.auto_deploy_permissions.
allow_auto_deploy_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_auto_deploy_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to the billing info for this account.
allow_billing_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_billing_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to the services in this account specified in
# var.dev_permitted_services.
allow_dev_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_dev_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed full (read
# and write) access to this account.
allow_full_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_full_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed IAM admin
# access to this account.
allow_iam_admin_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed read access
# to the logs in CloudTrail, AWS Config, and CloudWatch for this account. If
# var.cloudtrail_kms_key_arn is set, will also grant decrypt permissions for
# the KMS CMK.
allow_logs_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed read-only
# access to this account.
allow_read_only_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_read_only_access_iam_role_permissions_boundary = null
# A list of IAM ARNs from other AWS accounts that will be allowed read access
# to IAM groups and publish SSH keys. This is used for ssh-grunt.
allow_ssh_grunt_access_from_other_account_arns = []
# A list of IAM ARNs from other AWS accounts that will be allowed access to
# AWS support for this account.
allow_support_access_from_other_account_arns = []
# The ARN of the policy that is used to set the permissions boundary for the
# IAM role.
allow_support_access_iam_role_permissions_boundary = null
# What to name the auto deploy IAM role
auto_deploy_access_iam_role_name = "allow-auto-deploy-from-other-accounts"
# A list of IAM permissions (e.g. ec2:*) which will be granted for automated
# deployment.
auto_deploy_permissions = []
# What to name the billing access IAM role
billing_access_iam_role_name = "allow-billing-only-access-from-other-accounts"
# The ARN of a KMS CMK used to encrypt CloudTrail logs. If set, the logs IAM
# role will include permissions to decrypt using this CMK.
cloudtrail_kms_key_arn = null
# Set to false to have this module create no resources. This weird parameter
# exists solely because Terraform does not support conditional modules.
# Therefore, this is a hack to allow you to conditionally decide if the
# resources should be created or not.
create_resources = true
# What to name the dev access IAM role
dev_access_iam_role_name = "allow-dev-access-from-other-accounts"
# A list of AWS services for which the developers from the accounts in
# var.allow_dev_access_from_other_account_arns will receive full permissions.
# See
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_actions-resources-contextkeys.html
# to find the service name. For example, to grant developers access only to
# EC2 and Amazon Machine Learning, use the value ["ec2","machinelearning"]. Do
# NOT add iam to the list of services, or that will grant Developers de facto
# admin access.
dev_permitted_services = []
# What to name the full access IAM role
full_access_iam_role_name = "allow-full-access-from-other-accounts"
# What to name the IAM admin access IAM role
iam_admin_access_iam_role_name = "allow-iam-admin-access-from-other-accounts"
# Include this value as a prefix in the name of every IAM role created by this
# module. This is useful to prepend, for example, '<account-name>-' to every
# IAM role name: e.g., allow-full-access-from-other-accounts becomes
# stage-allow-full-access-from-other-accounts.
iam_role_name_prefix = ""
# What to name the logs access IAM role
logs_access_iam_role_name = "allow-logs-access-from-other-accounts"
# The maximum allowable session duration, in seconds, for the credentials you
# get when assuming the IAM roles created by this module. This variable
# applies to all IAM roles created by this module that are intended for people
# to use, such as allow-read-only-access-from-other-accounts. For IAM roles
# that are intended for machine users, such as
# allow-auto-deploy-from-other-accounts, see
# var.max_session_duration_machine_users.
max_session_duration_human_users = 43200
# The maximum allowable session duration, in seconds, for the credentials you
# get when assuming the IAM roles created by this module. This variable
# applies to all IAM roles created by this module that are intended for
# machine users, such as allow-auto-deploy-from-other-accounts. For IAM roles
# that are intended for human users, such as
# allow-read-only-access-from-other-accounts, see
# var.max_session_duration_human_users.
max_session_duration_machine_users = 3600
# What to name the read-only access IAM role
read_only_access_iam_role_name = "allow-read-only-access-from-other-accounts"
# What to name the ssh-grunt access IAM role
ssh_grunt_access_iam_role_name = "allow-ssh-grunt-access-from-other-accounts"
# What to name the support access IAM role
support_access_iam_role_name = "allow-support-access-from-other-accounts"
# A map of tags to apply to the IAM roles.
tags = {}
# When true, all IAM policies will be managed as dedicated policies rather
# than inline policies attached to the IAM roles. Dedicated managed policies
# are friendlier to automated policy checkers, which may scan a single
# resource for findings. As such, it is important to avoid inline policies
# when targeting compliance with various security standards.
use_managed_iam_policies = true
}
Reference
- Inputs
- Outputs
Required
aws_account_id
stringThe ID of the AWS Account.
Should we require that all IAM Users use Multi-Factor Authentication for both AWS API calls and the AWS Web Console? (true or false)
Optional
Allow GitHub Actions to assume the auto deploy IAM role using an OpenID Connect Provider. Refer to the docs for github-actions-iam-role for more information. Note that this is mutually exclusive with allow_auto_deploy_from_other_account_arns
.
object({
# ARN of the OpenID Connect Provider provisioned for GitHub Actions.
openid_connect_provider_arn = string
# URL of the OpenID Connect Provider provisioned for GitHub Actions.
openid_connect_provider_url = string
# Map of github repositories to the list of branches that are allowed to assume the IAM role. The repository should
# be encoded as org/repo-name (e.g., gruntwork-io/terrraform-aws-ci).
allowed_sources = map(list(string))
})
null
Example
default = {
openid_connect_provider_arn = "ARN"
openid_connect_provider_url = "URL"
allowed_sources = {
"gruntwork-io/terraform-aws-security" = ["main", "dev"]
}
}
Details
URL of the OpenID Connect Provider provisioned for GitHub Actions.
Details
Map of github repositories to the list of branches that are allowed to assume the IAM role. The repository should
be encoded as org/repo-name (e.g., gruntwork-io/terrraform-aws-ci).
allow_auto_deploy_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed to assume the auto deploy IAM role that has the permissions in auto_deploy_permissions
.
[]
Example
default = [
"arn:aws:iam::123445678910:role/jenkins"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
allow_billing_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed full (read and write) access to the billing info for this account.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
allow_dev_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed full (read and write) access to the services in this account specified in dev_permitted_services
.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
allow_full_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed full (read and write) access to this account.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
allow_iam_admin_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed IAM admin access to this account.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
allow_logs_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed read access to the logs in CloudTrail, AWS Config, and CloudWatch for this account. If cloudtrail_kms_key_arn
is set, will also grant decrypt permissions for the KMS CMK.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
allow_read_only_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed read-only access to this account.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
allow_ssh_grunt_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed read access to IAM groups and publish SSH keys. This is used for ssh-grunt.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
allow_support_access_from_other_account_arns
list(string)A list of IAM ARNs from other AWS accounts that will be allowed access to AWS support for this account.
[]
Example
default = [
"arn:aws:iam::123445678910:root"
]
The ARN of the policy that is used to set the permissions boundary for the IAM role.
null
What to name the auto deploy IAM role
"allow-auto-deploy-from-other-accounts"
auto_deploy_permissions
list(string)A list of IAM permissions (e.g. ec2:*) which will be granted for automated deployment.
[]
What to name the billing access IAM role
"allow-billing-only-access-from-other-accounts"
cloudtrail_kms_key_arn
stringThe ARN of a KMS CMK used to encrypt CloudTrail logs. If set, the logs IAM role will include permissions to decrypt using this CMK.
null
create_resources
boolSet to false to have this module create no resources. This weird parameter exists solely because Terraform does not support conditional modules. Therefore, this is a hack to allow you to conditionally decide if the resources should be created or not.
true
dev_access_iam_role_name
stringWhat to name the dev access IAM role
"allow-dev-access-from-other-accounts"
dev_permitted_services
list(string)A list of AWS services for which the developers from the accounts in allow_dev_access_from_other_account_arns
will receive full permissions. See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_actions-resources-contextkeys.html to find the service name. For example, to grant developers access only to EC2 and Amazon Machine Learning, use the value ['ec2','machinelearning']. Do NOT add iam to the list of services, or that will grant Developers de facto admin access.
[]
What to name the full access IAM role
"allow-full-access-from-other-accounts"
What to name the IAM admin access IAM role
"allow-iam-admin-access-from-other-accounts"
iam_role_name_prefix
stringInclude this value as a prefix in the name of every IAM role created by this module. This is useful to prepend, for example, '<account-name>-' to every IAM role name: e.g., allow-full-access-from-other-accounts becomes stage-allow-full-access-from-other-accounts.
""
What to name the logs access IAM role
"allow-logs-access-from-other-accounts"
The maximum allowable session duration, in seconds, for the credentials you get when assuming the IAM roles created by this module. This variable applies to all IAM roles created by this module that are intended for people to use, such as allow-read-only-access-from-other-accounts. For IAM roles that are intended for machine users, such as allow-auto-deploy-from-other-accounts, see max_session_duration_machine_users
.
43200
The maximum allowable session duration, in seconds, for the credentials you get when assuming the IAM roles created by this module. This variable applies to all IAM roles created by this module that are intended for machine users, such as allow-auto-deploy-from-other-accounts. For IAM roles that are intended for human users, such as allow-read-only-access-from-other-accounts, see max_session_duration_human_users
.
3600
What to name the read-only access IAM role
"allow-read-only-access-from-other-accounts"
What to name the ssh-grunt access IAM role
"allow-ssh-grunt-access-from-other-accounts"
What to name the support access IAM role
"allow-support-access-from-other-accounts"
tags
map(string)A map of tags to apply to the IAM roles.
{}
When true, all IAM policies will be managed as dedicated policies rather than inline policies attached to the IAM roles. Dedicated managed policies are friendlier to automated policy checkers, which may scan a single resource for findings. As such, it is important to avoid inline policies when targeting compliance with various security standards.
true