Browse the Repo

file-type-icon.circleci
file-type-icon.github
file-type-icon.patcher
file-type-icon_ci
file-type-icon_docs
file-type-iconcodegen
file-type-iconexamples
file-type-iconmodules
file-type-icon_deprecated
file-type-iconauto-update
file-type-iconaws-auth
file-type-iconaws-config-bucket
file-type-iconaws-config-multi-region
file-type-iconaws-config-rules
file-type-iconaws-config
file-type-iconaws-organizations
file-type-iconcloudtrail-bucket
file-type-iconcloudtrail
file-type-iconcross-account-iam-roles
file-type-iconcustom-iam-entity
file-type-iconebs-encryption-multi-region
file-type-iconebs-encryption
file-type-iconfail2ban
file-type-icongithub-actions-iam-role
file-type-iconguardduty-multi-region
file-type-iconguardduty
file-type-iconiam-access-analyzer-multi-region
file-type-iconiam-groups
file-type-iconiam-policies
file-type-iconREADME.md
file-type-iconmain.tf
file-type-iconoutputs.tf
file-type-iconvariables.tf
file-type-iconiam-user-password-policy
file-type-iconiam-users
file-type-iconip-lockdown
file-type-iconkms-cmk-replica
file-type-iconkms-grant-multi-region
file-type-iconkms-master-key-multi-region
file-type-iconkms-master-key
file-type-iconntp
file-type-iconos-hardening
file-type-iconprivate-s3-bucket
file-type-iconsaml-iam-roles
file-type-iconsecrets-manager-resource-policies
file-type-iconssh-grunt-selinux-policy
file-type-iconssh-grunt
file-type-iconssh-iam
file-type-iconssm-healthchecks-iam-permissions
file-type-icontls-cert-private
file-type-icontest
file-type-icon.editorconfig
file-type-icon.gitignore
file-type-icon.pre-commit-config.yaml
file-type-iconCODEOWNERS
file-type-iconLICENSE.txt
file-type-iconREADME.adoc
file-type-iconterraform-cloud-enterprise-private-module-...

Browse the Repo

file-type-icon.circleci
file-type-icon.github
file-type-icon.patcher
file-type-icon_ci
file-type-icon_docs
file-type-iconcodegen
file-type-iconexamples
file-type-iconmodules
file-type-icon_deprecated
file-type-iconauto-update
file-type-iconaws-auth
file-type-iconaws-config-bucket
file-type-iconaws-config-multi-region
file-type-iconaws-config-rules
file-type-iconaws-config
file-type-iconaws-organizations
file-type-iconcloudtrail-bucket
file-type-iconcloudtrail
file-type-iconcross-account-iam-roles
file-type-iconcustom-iam-entity
file-type-iconebs-encryption-multi-region
file-type-iconebs-encryption
file-type-iconfail2ban
file-type-icongithub-actions-iam-role
file-type-iconguardduty-multi-region
file-type-iconguardduty
file-type-iconiam-access-analyzer-multi-region
file-type-iconiam-groups
file-type-iconiam-policies
file-type-iconREADME.md
file-type-iconmain.tf
file-type-iconoutputs.tf
file-type-iconvariables.tf
file-type-iconiam-user-password-policy
file-type-iconiam-users
file-type-iconip-lockdown
file-type-iconkms-cmk-replica
file-type-iconkms-grant-multi-region
file-type-iconkms-master-key-multi-region
file-type-iconkms-master-key
file-type-iconntp
file-type-iconos-hardening
file-type-iconprivate-s3-bucket
file-type-iconsaml-iam-roles
file-type-iconsecrets-manager-resource-policies
file-type-iconssh-grunt-selinux-policy
file-type-iconssh-grunt
file-type-iconssh-iam
file-type-iconssm-healthchecks-iam-permissions
file-type-icontls-cert-private
file-type-icontest
file-type-icon.editorconfig
file-type-icon.gitignore
file-type-icon.pre-commit-config.yaml
file-type-iconCODEOWNERS
file-type-iconLICENSE.txt
file-type-iconREADME.adoc
file-type-iconterraform-cloud-enterprise-private-module-...
ssh-grunt

ssh-grunt

Manage SSH access to EC2 Instances using groups in AWS IAM or your Identity Provider (e.g., ADFS, Google, Okta, etc).

Code Preview

Preview the Code

mobile file icon

README.md

down

A Best-Practices Set of IAM Policy Documents

This Gruntwork Terraform Module sets up a set of IAM Policy Documents that can be used in IAM users, groups, and roles. The documents represent a reasonable collection of permissions that will make sense for most organizations for managing different permissions levels in your AWS account.

Note that these documents are Terraform data sources, so they don't create anything themselves and are not intended to be used on their own. The way to use them is to take the outputs from this module (which are all JSON IAM documents) and plug them into other Terraform resources, such as aws_iam_policy, aws_iam_user_policy, aws_iam_group_policy, and aws_iam_role_policy. See the iam-groups and cross-account-iam-roles modules for examples.

If you're not familiar with IAM concepts, start with the Background Information section as a way to familiarize yourself with the terminology.

Motivation

In Summer 2014, a company called CodeSpaces that offered "rock solid, secure, and affordable git hosting and project management" was forced to shut down after a single rogue employee entered its AWS account and wiped out everything (See ArsTechnica Article). The goal of this module is to carefully manage access to your AWS account to reduce the chances of rogue employees or external attackers being able to do too much damage.

How do you use this module?

You use this module like any other Terraform module:

module "iam_policies" {
  source = "../iam-policies"

  aws_account_id = "123456789012"
  trust_policy_should_require_mfa = true
  iam_policy_should_require_mfa = true
  dev_s3_bucket_prefix = "my-company.dev"
  dev_permitted_services = ["ec2"]
}

You can now access all of the documents as outputs on the module. E.g.:

resource "aws_iam_group_policy" "full_access" {
  name = "full-access"
  group = "${aws_iam_group.full_access.id}"
  policy = "${module.iam_policies.full_access}"
}

You can find the full list of outputs in outputs.tf.

Check out the iam-groups and cross-account-iam-roles modules for example code.

IAM Policy Documents created

This module creates the following IAM Policy documents:

  • full-access: provides full access to all resources in the AWS account.

  • billing: provides read and write billing settings, but nothing else.

  • logs: provides read access to logs in CloudTrail, AWS Config, and CloudWatch. Since CloudTrail logs may be encrypted with a KMS CMK, if var.cloudtrail_kms_key_arn is set, these users will also get permissions to decrypt using this KMS CMK.

  • developers: provides whatever permissions are declared in var.dev_permitted_services. In addition, creates permissions for a personal S3 bucket named <var.dev_permitted_services><iam-user-name>.

  • read-only: provides read access to all resources in the AWS account but have no write privileges.

  • use-existing-iam-roles: allows passing existing IAM Roles to AWS resources to which you have been granted access. Does not allow creating new IAM Roles. See below for more information.

  • iam-user-self-mgmt: provides permission to manage your own IAM User account. This includes resetting the IAM User password, and generating AWS account credentials. It also grants permission to list other IAM Users, but not to view any information about them.

  • iam-admin: provides permission to manage all IAM entities. This includes managing users, groups, roles, and policies. You might want this if you need to allow ongoing management of an account but don't want to grant full administrator (*:*) access explicitly.

  • allow_access_to_other_accounts: provides permission to assume an IAM role in another AWS account. This makes cross-account access, easy, where you can have all your users defined in one AWS account (e.g. users) and to grant those users access to certain IAM roles in other AWS accounts (e.g. stage, prod). The documents that are created and which IAM roles they have access to is controlled by the variable var.allow_access_to_other_account_arns.

  • allow_access_to_all_other_accounts: provides permission to assume an IAM role in all the external AWS accounts specified in var.allow_access_to_other_account_arns.

  • allow_access_from_other_accounts: allows users from other AWS accounts to assume specific roles in this account. This makes cross-account access, easy, where you can have all your users defined in one AWS account (e.g. users) and to grant those users access to certain IAM roles in other AWS accounts (e.g. stage, prod). The documents that are created and which IAM roles they have access to is controlled by the variable var.allow_access_from_other_account_arns.

  • ssh_grunt_permissions: provides the permissions ssh-grunt needs to validate SSH keys with IAM.

  • ssh_grunt_houston_permissions: provides the permissions ssh-grunt needs to validate SSH keys with Houston.

  • auto_deploy_permissions: provides the permissions in var.auto_deploy_permissions to do automated deployment. The primary use case is to add these permissions to the IAM role of a CI server (e.g. Jenkins).

  • allow_auto_deploy_from_other_accounts: allows the IAM ARNs in var.allow_auto_deploy_from_other_account_arns to do automated deployment using the permissions in var.auto_deploy_permissions. The primary use cases is to allow a CI server (e.g. Jenkins) in another AWS account to do automated deployments in this AWS account.

Additional Guidelines

The Root AWS Account

When you first create your AWS account, only the root AWS account exists. While logged in as the root user, your first and only step should be to create a small number of IAM Users and assign them the FullAccess AWS managed policy so that they can then configure your AWS account as needed using their IAM User accounts.

Now delete the root account's access keys (the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) and store the root AWS account password in a very safe place. You might also consider setting up a Multi-Factor Authentication (MFA) device on your root account such as Authy or Google Authenticator.

Note that AWS only allows a single MFA device per account. This means that if you choose to use MFA on your root account, you should save the initializing QR code along with the password! Otherwise, you may need to contact AWS to restore access to your account. Another alternative is to initialize more than one device against the same MFA code.

Or for some interesting possibilities, see the Authy article around "multi multi-factor" authentication.

Background Information

What is IAM?

AWS Identity and Access Management (IAM) is a set of features in every AWS account that can be used to manage and secure human users, human groups, and AWS Resources.

IAM Users

Human users access the AWS Web Console or AWS API as IAM Users. Usually, an IAM User corresponds to a single human, but sometimes you create IAM Users for machines, like a circleci IAM User.

It's convenient to be able to differentiate between different types of IAM Users, so we recommend using some kind of common prefix for different IAM User types. For example:

  • jane.doe (an employee of your org)
  • _machine.jenkins (perhaps machine users are denoted with a _)
  • _contractor.john.doe (contractors are called out explicitly)

IAM Users can assert their permissions via the AWS Web Console or AWS API. The awscli and various AWS SDKs all just implement performant ways of connecting to the AWS API.

IAM Policies

Once you've created an IAM User, that user has no permissions to do anything. You must grant that user specific permissions by attaching one or more IAM Policies.

An IAM Policy is simply a JSON document that declares a set of permissions. For example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "rds:*",
        "lambda:*",
        "ec2:*"
      ],
      "Resource": "*"
    }
  ]
}

This particular IAM Policy "Allows" all permissions on all rds, lambda and ec2 resources.

Each AWS resource type has a set of IAM permissions associated with it. For example, for EC2 Instances, some of the IAM permissions include:

  • ec2:CreateTags
  • ec2:DeleteTags
  • ec2:StartInstances
  • ec2:StopInstances

So in the above example IAM Policy, the action ec2:* actually says that this Policy grants all permissions on EC2 Resources. It could have granted this permission only to certain EC2 Instances, but thanks to Resource: "*", this permission applies to all EC2 resources.

For more on IAM Policies, see the official docs.

IAM Groups

You might be tempted to directly attach permissions to IAM Users, but it's a best practice to instead grant permissions through IAM Groups by adding IAM Users to one or more IAM Groups.

Using IAM Groups means keeping track of permissions on a small number of groups, rather than a potentially large number of IAM Users.

IAM Roles

Sometimes AWS resources themselves need permissions on other AWS resources. For example, an EC2 Instance or Lambda Function might need to access a file in an S3 Bucket. While you could hard-code your IAM User credentials in these resources, hard-coding credentials anywhere is almost always a bad idea since they are now discoverable, non-auditable, and more likely to leak.

Fortunately, AWS provides an alternative, IAM Roles. IAM Roles can be granted permissions via IAM Policies, just like with IAM Users and IAM Groups. In addition, an AWS Resource can "assume" an IAM Role and inherit all its permissions. The process of assuming an IAM Role is handled transparently and securely by AWS.

The Three Levels of IAM Permissions

Why do we have a use-existing-iam-roles IAM Group? It's because it represents an "intermediate" level of permissions on the AWS account. So what's an "intermediate" level of permissions?

A key insight in configuring IAM Policies is that an IAM User who has permission to create other permissions can give herself any arbitrary permissions and thereby become the equivalent of an admin user. For this reason, we must limit the permission to create permissions.

The following hierarchy is a conceptual model that proposes one such way. Consider this a way of thinking about IAM Permissions, not an exact prescription for implementation:

  1. Full IAM Permissions -- This user is equivalent to root and can do anything in the AWS account, including creating new IAM Roles.

    Corresponds to the "admin" IAM Group above.

  2. Leverage Existing IAM Roles -- This user cannot create a new IAM Role, but can leverage existing IAM Roles when launching AWS resources like an EC2 Instance, Lambda job, or ECS Task.

    For example, when launching an EC2 Instance, this user can't create her own IAM Role for that EC2 Instance, but she can choose among existing IAM Roles. Presumably, no IAM Role would itself have the ability to create permissions.

    Corresponds to any non-admin IAM Group plus the "use-existing-iam-roles" group above. For example, an IAM User would belong both to an IAM Group that grants certain permissions (e.g. launch EC2 Instances) and also to the "use-existing-iam-role" group.

  3. Leverage No IAM Roles at All -- This user cannot pass any IAM Roles to any AWS resources, but may have other permissions with respect to AWS resources granted by other IAM Policies or IAM Groups.

    Corresponds to an IAM User belonging to a custom IAM Group an organization might create without also belonging to the "use-existing-iam-roles" group above.

What this model tells us is that all IAM Users must fall into one of these three categories. As an example, if an IAM User requires the ability to define IAM Roles as part of her job, there's no point limiting this IAM User's permissions. Instead, just consider them an admin user.

How do you know what to include in an IAM Policy?

We use a combination of our own personal experience and the AWS Managed Policies for Job Functions as a reference. Note that none of the AWS Managed Policies allows us to directly specify a condition property, which means we can't enforce multi-factor authentication (MFA) on these policies. As a result, we've created our own policies, written automated tests for them, and of course will continue to maintain them over time.

Gotcha's

Avoid the Terraform resource aws_iam_policy_attachment

Be very careful about using the aws.aws_iam_policy_attachment Terraform resource. Using this resource with a Managed IAM Policy will remove any other IAM Users, IAM Groups, or IAM Roles that have attached that Managed Policy.

Instead, use these Terraform resources so you don't have to worry about this problem:

TODO

Are we missing any functionality? Let us know by emailing info@gruntwork.io!

Questions? Ask away.

We're here to talk about our services, answer any questions, give advice, or just to chat.

Ready to hand off the Gruntwork?