Login to the IAM console and click on your User Name in the Users section.
At the bottom of the Security Credentials tab, click the "Upload SSH public key" button, and enter the contents of
your public SSH key (which is typically stored in ~/.ssh/id_rsa.pub):
Install ssh-grunt on your servers
ssh-grunt consists of a single binary. The easiest way to get it onto your servers is to use the Gruntwork
Installer (make sure to replace <VERSION> below with the latest
version from the releases page):
Important note: We recommend installing ssh-grunt as part of a Packer template and
building an AMI with it. If you are installing ssh-grunt interactively (e.g., for learning / experimentation) or
as part of a User Data script, then you must restart sshd in order for the changes above to take effect! E.g.,
depending on your OS, you'd have to run something like:
sudo service sshd reload
Once the binary is on the server, use ssh-grunt to complete the configuration:
ssh-grunt iam install \
--iam-groupssh-group \
--iam-group-sudo ssh-sudo-group
The install command does two things:
Create a cron job to run ssh-grunt iam sync-users to periodically (by default, every 30 minutes) sync user accounts
from the IAM Groups specified via the --iam-group and --iam-group-sudo option.
Configure SSH to use ssh-grunt iam print-keys to authenticate login attempts using public keys in IAM.
Important note: If ec2-instance-connect is installed, it will conflict with the operability of ssh-grunt.
When you run the install command, it will detect the existence of ec2-instance-connect and warn you. The easiest
solution is to remove the ec2-instance-connect package via apt-get remove or yum remove.
You can pass in multiple --iam-group and --iam-group-sudo to sync users associated with different IAM groups. For
example, if you ran:
ssh-grunt iam install \
--iam-groupssh-group-dev \
--iam-groupssh-group-stage
ssh-grunt will sync users associated with EITHER the ssh-group-dev IAM group or ssh-group-stage IAM group.
See the CLI docs for the full list of available options.
Set up IAM permissions
You need to configure IAM permissions on each server where ssh-grunt is running so that it can access your IdP:
The IAM permissions you need to configure for ssh-grunt depend on whether your infrastructure is deployed in a
single AWS account or multiple AWS accounts:
ssh-grunt retrieves info from IAM using the AWS API. To use the API, ssh-grunt needs:
AWS credentials: the best way to provide credentials is to attach an IAM
Role to the EC2 Instance.
IAM permissions: ssh-grunt needs an IAM
Policy that allows the iam:GetGroup,
iam:ListSSHPublicKeys, and iam:GetSSHPublicKey actions. The iam-policies module can
provide the IAM policy with these permissions for you in the output variable ssh_grunt_permissions.
If you have multiple AWS accounts, with all IAM users defined in one account (e.g., the "security" account), and EC2
Instances running in various other AWS accounts (e.g., the "dev" and "prod" accounts), then you need to give
ssh-grunt running on those EC2 Instances permissions to access the account where users and groups are defined:
In the AWS account where the IAM users are defined, use the cross-account-iam-roles
module to create an IAM role that allows your other AWS account(s) to access IAM
Group and public SSH key info by specifying the ARNs of those other accounts in the
allow_ssh_grunt_access_from_other_account_arns input variable. Rough example:
In the AWS accounts where ssh-grunt is running, give the EC2 Instances that run ssh-grunt an IAM role that has
permissions to assume an IAM role in the users account. You can create the IAM policy with this permission using
the iam-policies module by specifying the ARN of the IAM role you created in the users
account in the previous step in the allow_access_to_other_account_arns input variable and adding the policy in
the allow_access_to_other_accounts output variable to the EC2 Instance's IAM role.
module"iam_policies" {
source = "git::git@github.com:gruntwork-io/terraform-aws-security.git//modules/iam-policies?ref=v1.0.8"# ssh-grunt is an automated app, so we can't use MFA with it
trust_policy_should_require_mfa = false
iam_policy_should_require_mfa = false
allow_access_to_other_account_arns = [["arn:aws:iam::111111111111:role/allow-ssh-grunt-access-from-other-accounts"]]
# ... (other params ommitted) ...
}
resource"aws_iam_role_policy""ssh_grunt_external_account_permissions" {
name = "ssh-grunt-external-account-permissions"
role = "${module.example_instance.iam_role_id}"
policy = "${element(module.iam_policies.allow_access_to_other_accounts, 0)}"
}
When you're calling ssh-grunt iam install, pass the ARN of the IAM role from the other account using --role-arn
argument.
ssh-grunt iam install \
--iam-group ssh-users \
--role-arn arn:aws:iam::111111111111:role/allow-ssh-grunt-access-from-other-accounts
Check out the ssh-grunt example for sample code and pay attention to the external_account_arn
input variable.
Test it out
You should now be able to SSH to your servers using your IdP user name and public key (note, if a server has just
booted, it will only sync users from your IdP after ~90 seconds, so be patient!). For example, if you installed
ssh-grunt on an EC2 Instance with IP address 11.22.33.44 and your IdP user name is grunt, you can now connect to
the server as follows:
ssh grunt@11.22.33.44
That's all there is to it! No Key Pair files or passwords to worry about and as you update users in IAM, your servers
will sync up automatically!
To learn more, check out the How it works docs to see what's happening under the hood, and the
CLI docs to learn all the parameters and options you can tweak.
When you run ssh-grunt iam install, it adds a cron job that periodically runs the ssh-grunt iam sync-users command.
The sync-users command does the following:
Fetch the users from the IAM Group specified via the --iam-group option and for each one, create an OS user on
the EC2 Instance. All of these OS users get added to the OS group ssh-grunt-non-sudo-group.
Fetch the users from the IAM Group specified via the --iam-group-sudo option and for each one, create an OS user
that has sudo privileges on the EC2 Instance. All of these OS users get added to the OS group ssh-grunt-sudo-group.
Remove any users in the ssh-grunt-non-sudo-group and ssh-grunt-sudo-group groups that are not in the corresponding
IAM group.
A note on user names
Note that the requirements for OS user names are stricter than those of other IdPs, such as IAM. Therefore, the OS user
name created by the sync-users command may not exactly match your IdP user name. In particular, OS user names must
start with a letter, followed by letters, numbers, underscores, and dashes, and be no more than 32 characters long.
Therefore, ssh-grunt does the following:
Drop anything after the @ symbol in email addresses (e.g. "foo@bar.com" --> "foo").
Replace whitespace and periods with underscores (e.g. "foo.bar baz" --> "foo_bar_baz").
Drop all other illegal characters (e.g. "foo$@%,!bar" --> "foobar").
Drop any leading punctuation or numbers (e.g. ".,123foo" --> "foo").
Truncate all strings over 32 characters long.
We store the original user name in the comment field of the OS user so we can retrieve it when the user tries to
authenticate with their public key.
Authenticating requests with public keys
When you run install command of ssh-grunt, it modifies the AuthorizedKeysCommand in /etc/ssh/sshd_config. When
a user tries to connect via SSH, SSH will execute the AuthorizedKeysCommand (passing it the username as the first
argument) and whatever text that command writes to stdout will be used as the authorized_keys—that is, the list of
public keys that are allowed to connect to the server.
We take advantage of this AuthorizedKeysCommand by configuring it to run ssh-grunt iam print-keys,
which looks up the user's public keys in IAM and prints all the
active keys to stdout. That way, all a user has to do is upload their public keys to IAM and they will be
able to authenticate to any server with ssh-grunt.
Note that SSH is very picky about the program it executes for the AuthorizedKeysCommand (See the sshd_config
docs for details):
The program must not use any custom arguments, must be owned by root, must not be writable by group or others, and
must be specified by an absolute path. To meet these requirements, we create a script under /opt/ssh-grunt that runs
the print-keys command of ssh-grunt.
The program must be executed under a user specified via the AuthorizedKeysCommandUser configuration. By default,
we set this configuration to the user that runs the install command of ssh-grunt.
You can run ssh-grunt --help at any time to see the CLI docs.
iam print-keys command
Usage: ssh-grunt iam print-keys [OPTIONS] USERNAME
Description: Find the public keys stored for the specified IAM user and print them to stdout.
Arguments:
USERNAME (required): Look up the public keys for this IAM user name.
Options:
--role-arn (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and
groups are defined in another AWS account.
Examples:
ssh-grunt iam print-keys grunt
iam sync-users command
Usage: ssh-grunt iam sync-users [OPTIONS]
Description: Sync the user accounts on this system with the user accounts in the specified IAM groups.
Options:
--iam-group (optional): Sync the user accounts on this system with the user accounts in this IAM group. At least
one of --iam-group or --iam-group-sudo is required.
--iam-group-sudo (optional): Sync the user accounts on this system with the user accounts in this IAM group and
give these user accounts sudo privileges. At least one of --iam-group or --iam-group-sudo is required.
--role-arn (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and
groups are defined in another AWS account.
--force-user-deletion (optional): If this flag is set, delete not only the OS user, but also their home directory
when that user is removed from an ssh-grunt managed group.
--dry-run (optional): Print out what this command would do, but don't actually make any changes on this system.
Examples:
ssh-grunt iam sync-users \
--iam-groupssh-group \
--iam-group-sudo ssh-sudo-group
iam install command
Usage: ssh-grunt iam install [OPTIONS]
Description: Configure this server to a) periodically sync user accounts from IAM and b) use ssh-grunt to authenticate
SSH connections.
Options:
--iam-group (optional): Sync the user accounts on this system with the user accounts in this IAM group. At least
one of --iam-group or --iam-group-sudo is required.
--iam-group-sudo (optional): Sync the user accounts on this system with the user accounts in this IAM group and
give these user accounts sudo privileges. At least one of --iam-group or --iam-group-sudo is required.
--cron-schedule (optional): A cron expression that controls how often ssh-grunt syncs IAM users to this system.
Default: */30 * * * * (every 30 minutes).
--authorized-keys-command-user (optional): The user that should execute the SSH AuthorizedKeysCommand. Default:
current user.
--role-arn (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and
groups are defined in another AWS account.
--force-user-deletion (optional): If this flag is set, delete not only the OS user, but also their home directory
when that user is removed from an ssh-grunt managed group.
--dry-run (optional): Print out what this command would do, but don't actually make any changes on this system.
Examples:
ssh-grunt iam install \
--iam-groupssh-users \
--iam-group-sudo ssh-sudo-users
Threat model
The threat model is defined in terms of what each possible attacker can achieve.
At a high level, the security of ssh-grunt is predicated on the security of SSH, your IdP, and Gruntwork.
Assumptions
Your users act reasonably and do not reveal their secrets, such as their private SSH keys or IdP credentials.
SSH is a secure protocol and public/private key encryption guarantees are valid.
The AWS APIs are properly secured by TLS and IAM Roles.
The user's computer and your servers are not compromised by malware.
The copy of ssh-grunt running on your servers has not been compromised by malware.
Threats from an SSH compromise
If an attacker gets access to one of your developer's private keys, they will be able to:
Make arbitrary changes on the server, especially if your developer had sudo access.
Use any IAM Roles attached to that server to authenticate to the AWS APIs. In particular, the IAM Roles you need to
use ssh-grunt will allow the attacker to list the user names and public keys of other SSH users.
Possible remediation: Delete the compromised key from IAM as soon as possible, and the attacker will no
longer be able to connect to your servers.
Threats from an IAM compromise
If you are using gruntssh with IAM, and your server cannot communicate with IAM, either due to an outage in AWS or a
misconfiguration on your servers:
Your developers will not be able to authenticate to your servers using their public keys.
User accounts will no longer automatically sync to the servers, so changes in IAM groups will not be reflected on
your servers.
Possible remediation: Always launch servers with an EC2 Key
Pair as backup. This Key Pair should kept on
a trusted admin's computer, not shared with anyone else (if you must share it, make sure to encrypt it thoroughly using
something like KMS or Keybase), and only used in case of
emergencies.
If an attacker gets access to an IAM user account, they will be able to:
Make arbitrary changes to your AWS account, depending on the permissions attached to that IAM account.
Add their own public key to their IAM account and add that account to an IAM group that has SSH access. This will
allow them to SSH to your servers using their public key and make arbitrary changes.
If an attacker gets access to a user account in the IdP (e.g., ADFS or Google), they
will be able to:
Make arbitrary changes to in the IdP itself, depending on the permissions attached to that IdP user.
Make arbitrary changes to your AWS account, depending on the permissions attached to that IdP user.
Possible remediation: ensure you require multi-factor authentication for your IdP and require all users to use secure
passwords to reduce the chances of a compromised account.
Threats from a Gruntwork compromise
If an attacker gets access to Gruntwork's repos, they will be able to:
Replace the ssh-grunt binary in the terraform-aws-security repo with one
that contains malware. This will allow the attacker to make arbitrary changes on any server where ssh-grunt is
installed.
Possible remediation: Gruntwork only grants write access to its repos to employees, all of whom are required to use
Multi-Factor Authentication and strong passwords. In the future, we will publish checksums of our binaries in separate
locations so you can use those to confirm that the binary you are installing is an authentic one.
Developing ssh-grunt
Since ssh-grunt makes lots of changes to the OS (creating users, modifying SSH settings, etc), we recommend running it
in a Docker container.
Building the Docker image
The Docker image is defined in the Dockerfile. To build it, run:
dockerbuild -t gruntwork/ssh-grunt .
Running locally
To run the app locally, we've defined a docker-compose.yml file that mounts source code into the Docker container
(so you don't have to keep rebuilding the container when you make source changes) and forwards our AWS environment
variables. To run the app with Docker Compose:
docker-compose run ssh-grunt [ARGS...]
For example:
docker-compose run ssh-grunt iam print-keys myuser
Stacktraces
If you run the app and it crashes on you, set the SSH_GRUNT_DEBUG environment variable to any value to see the
stacktrace:
docker-compose run -e SSH_GRUNT_DEBUG=true ssh-grunt iam print-keys myuser
Running tests
Note: the automated tests for this repo (a) make many changes in the OS, include creating lots of OS users, so
we only recommend running them within a Docker container and (b) create and delete real IAM users and groups in your
AWS account, so always let them run to completion so they can do proper cleanup.
To run all the tests, use the test.sh script, which uses Docker Compose under the hood:
./_ci/test.sh
To run a specific test, use the -run argument:
./_ci/test.sh -run TestFoo
Possible future additions
Some items we are considering for the future:
Set up two-factor auth (2FA) using libpam-google-authenticator.
Lock down SSH settings by disabling password authentication and the root user.
Lock down SSH even more: https://stribika.github.io/2015/01/04/secure-secure-shell.html
Send notifications for all server access: https://www.inversoft.com/guides/2016-guide-to-user-data-security#intrusion-detection
If you're interested in these features, let us know!
Questions? Ask away.
We're here to talk about our services, answer any questions, give advice, or just to chat.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"f50030b8a32796fb180504b479f11cd621dfbb21"}]},{"name":".editorconfig","path":".editorconfig","sha":"a5eec1063e66c4cb953cba222dd50b4d314ef3e2"},{"name":".gitignore","path":".gitignore","sha":"7c6465427ce13118c172efcfae41587f606d0349"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","sha":"8d98e6d06e9c4d3f9b680dc9ab6d5ccc7f9d96d3"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"7ab1528db56eca5c136e005f4f08ec9b2c0f3aeb"},{"name":"LICENSE.txt","path":"LICENSE.txt","sha":"f4e3d9bd4717a044ed31ad847a300eee74371a78"},{"name":"README.adoc","path":"README.adoc","sha":"20a05e1a721fc06b60430388648cb3e2dad846cc"},{"name":"_ci","children":[{"name":"output-debug-values.sh","path":"_ci/output-debug-values.sh","sha":"39d6d5f080a53f932e3b5ec970b5f268fd00e50a"}]},{"name":"_docs","children":[{"name":"auto-update.png","path":"_docs/auto-update.png","sha":"77bfd1c65de0245ac8b3c67d5b0b64fc440824bf"},{"name":"aws-cloudtrail-architecture.png","path":"_docs/aws-cloudtrail-architecture.png","sha":"a2dd9a08b8ed77744fd5febab3be7bdf633dee79"},{"name":"aws-cloudtrail.png","path":"_docs/aws-cloudtrail.png","sha":"acc7dcaf4b46ce3cef1bcc20be0329e12c320e7f"},{"name":"aws-config-architecture.png","path":"_docs/aws-config-architecture.png","sha":"721458048d5e539468c438498863a91fa96e0a85"},{"name":"aws-config-rules-architecture.png","path":"_docs/aws-config-rules-architecture.png","sha":"29fe3f20358b176e385d1bcdc0357bff2c1d5b4a"},{"name":"aws-config-rules.png","path":"_docs/aws-config-rules.png","sha":"ac3f7b35bcac949887e62aee260d9cb70edd3ae8"},{"name":"aws-config.png","path":"_docs/aws-config.png","sha":"02f4b326aef57372def4f3fafa4f0e4cec07e395"},{"name":"aws-guardduty.png","path":"_docs/aws-guardduty.png","sha":"053b92412fb8e3fb5740acc404b493fe1dd7229b"},{"name":"aws-organizations-architecture.png","path":"_docs/aws-organizations-architecture.png","sha":"bd57412fe85d3fe8d5e358db5e3b7bfef3e786a9"},{"name":"aws-organizations-icon.png","path":"_docs/aws-organizations-icon.png","sha":"b2b3fa04f51a23e5bae1b3389ffedf5e17b3cef2"},{"name":"iam-access-analyzer.png","path":"_docs/iam-access-analyzer.png","sha":"36e38e69454beae66d35b9bf25b3e5ffe1e68a25"},{"name":"kms-icon.png","path":"_docs/kms-icon.png","sha":"cd4f350a9a3fda41089928a7e396ee8924b7a901"},{"name":"multi-account-multi-region-aws-config.png","path":"_docs/multi-account-multi-region-aws-config.png","sha":"a9c813b1799fe71554c20c8fefc703792293bfe4"},{"name":"multiaccount_guardduty.png","path":"_docs/multiaccount_guardduty.png","sha":"c56b50bbb4c2a041366b430cada27b88aa02524b"},{"name":"ssh-grunt-architecture.png","path":"_docs/ssh-grunt-architecture.png","sha":"9ced8c68bcc7957e50aa016cad6c5b043a05b470"},{"name":"terminal-icon.png","path":"_docs/terminal-icon.png","sha":"df09d52d5b1176d7e231bab6c7712c3728e45c1b"}]},{"name":"codegen","children":[{"name":"README.adoc","path":"codegen/README.adoc","sha":"143d07fec60ff6b82003aefd6c2fb39a3e9d6e63"},{"name":"core-concepts.md","path":"codegen/core-concepts.md","sha":"824cb1918965823abd41d4fc34d91815abb42abf"},{"name":"generate-all.sh","path":"codegen/generate-all.sh","sha":"e95f7a1fe3b75636468472cd072e0d0b559f2eb5"},{"name":"generate-aws-config","children":[{"name":".gitignore","path":"codegen/generate-aws-config/.gitignore","sha":"b488f31b176e8da6501add7ce148074af2337d91"},{"name":"main.go","path":"codegen/generate-aws-config/main.go","sha":"fbdc3f3df8ccf910430acad3d7d29e8b7d584cd2"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-aws-config/static/README.adoc","sha":"fb308d4303343786cde18f5f830e313c13800c5c"},{"name":"core-concepts.md","path":"codegen/generate-aws-config/static/core-concepts.md","sha":"976e6424dcb277f70377f92eb2a10d0c8e595a85"},{"name":"variables.tf","path":"codegen/generate-aws-config/static/variables.tf","sha":"86f014396e15600dfd6e2772ef018539eaca55ae"}]},{"name":"template_data.go","path":"codegen/generate-aws-config/template_data.go","sha":"a6c477a60ec628a89f6a7e78c927974eff566666"}]},{"name":"generate-aws-guardduty","children":[{"name":".gitignore","path":"codegen/generate-aws-guardduty/.gitignore","sha":"b488f31b176e8da6501add7ce148074af2337d91"},{"name":"main.go","path":"codegen/generate-aws-guardduty/main.go","sha":"65a8af5a54afd75c1123cf9905cac3a770ca210d"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-aws-guardduty/static/README.adoc","sha":"ab5259fd33416948231b5d9c4852ac5981b49540"},{"name":"variables.tf","path":"codegen/generate-aws-guardduty/static/variables.tf","sha":"992199e9e968a3006918b286c7f3e69eb2fbbd74"}]},{"name":"template_data.go","path":"codegen/generate-aws-guardduty/template_data.go","sha":"99aa2d3dd6e70fa736e6101e0ede935a59cec955"}]},{"name":"generate-ebs-encryption","children":[{"name":".gitignore","path":"codegen/generate-ebs-encryption/.gitignore","sha":"a3f620a6c9c87b381bf6748917bdf9542792f54b"},{"name":"main.go","path":"codegen/generate-ebs-encryption/main.go","sha":"d5642a928632991c5863c7a895fb4f1bd09f9922"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-ebs-encryption/static/README.adoc","sha":"f452559ca803195574f30ae6323f54b58f91aaa3"},{"name":"variables.tf","path":"codegen/generate-ebs-encryption/static/variables.tf","sha":"abe1386cf0824d0d76dd3d01f3f7682e751a0379"}]},{"name":"template_data.go","path":"codegen/generate-ebs-encryption/template_data.go","sha":"ce345f397a069d5d2f66ebef287fe47a1a8304db"}]},{"name":"generate-multiregion-iam-access-analyzer","children":[{"name":".gitignore","path":"codegen/generate-multiregion-iam-access-analyzer/.gitignore","sha":"045b82ea48805332afcf6edb7a52b41310f0c72c"},{"name":"main.go","path":"codegen/generate-multiregion-iam-access-analyzer/main.go","sha":"5d00017ea9e19f4e16612e7f4cb1e24c454b2279"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-multiregion-iam-access-analyzer/static/README.adoc","sha":"069ee2ac36dc7525a1598ed994b5671ad945b73e"},{"name":"core-concepts.md","path":"codegen/generate-multiregion-iam-access-analyzer/static/core-concepts.md","sha":"6bbaac3d7e62744e3fe3f511cd4ae78b212d08a8"},{"name":"variables.tf","path":"codegen/generate-multiregion-iam-access-analyzer/static/variables.tf","sha":"fe5c514084fbbe9ef542e6b849c37b5c81739cd0"}]},{"name":"template_data.go","path":"codegen/generate-multiregion-iam-access-analyzer/template_data.go","sha":"7a3ad0318a8fd01753acacc41572f2a629d2ce4d"}]},{"name":"generate-multiregion-kms-grant","children":[{"name":".gitignore","path":"codegen/generate-multiregion-kms-grant/.gitignore","sha":"ce81abc8eeae39683199307d44536f0a8b1b7862"},{"name":"main.go","path":"codegen/generate-multiregion-kms-grant/main.go","sha":"b2de863570dc8b0beb69d015ac3b656fc6af6fbb"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-multiregion-kms-grant/static/README.adoc","sha":"fea6fb06a33f23861f1660b49d1bbafa63e92c48"},{"name":"core-concepts.md","path":"codegen/generate-multiregion-kms-grant/static/core-concepts.md","sha":"3eb1725fa927a84cc2a0341335d150bf5c6e70f5"},{"name":"variables.tf","path":"codegen/generate-multiregion-kms-grant/static/variables.tf","sha":"d27a8da6b13e1ea67a1b4721edd8bbe59781df7d"}]},{"name":"template_data.go","path":"codegen/generate-multiregion-kms-grant/template_data.go","sha":"1113e3958e601ba5f1639b97cdec4d4d80e0e9a1"}]},{"name":"generate-multiregion-kms","children":[{"name":".gitignore","path":"codegen/generate-multiregion-kms/.gitignore","sha":"dd60654458233c0bdb18892c5989f1828889d55b"},{"name":"main.go","path":"codegen/generate-multiregion-kms/main.go","sha":"a4c0e0fefe40a90d724a054ceef68745871eb6e6"},{"name":"static","children":[{"name":"README.adoc","path":"codegen/generate-multiregion-kms/static/README.adoc","sha":"73f3c01b25a01bda21f3ea98c28a54c3b8b3ab89"},{"name":"variables.tf","path":"codegen/generate-multiregion-kms/static/variables.tf","sha":"f97ad1ca562b31afbddfb35aebb5cb1f772191c9"}]},{"name":"template_data.go","path":"codegen/generate-multiregion-kms/template_data.go","sha":"7ec2a39c066905afa345fd07881681f199ad700f"}]},{"name":"generator","children":[{"name":"aws.go","path":"codegen/generator/aws.go","sha":"5c4712b16f00ebfe3d9ab85e5ef7ec4e7376bd7e"},{"name":"cli.go","path":"codegen/generator/cli.go","sha":"6e92f692f11d26c182c9e987fd566b0b8cb10901"},{"name":"errors.go","path":"codegen/generator/errors.go","sha":"21fd1f6d4bef60ea9cb39939783696526ddd02e7"},{"name":"generator.go","path":"codegen/generator/generator.go","sha":"512cd371bdf1342885f4313f4bb607137f8e51f8"},{"name":"main.tf.tpl.go","path":"codegen/generator/main.tf.tpl.go","sha":"74a04bfcd190dfbb669f9856c83059ca5a9bc6fd"},{"name":"outputs.tf.tpl.go","path":"codegen/generator/outputs.tf.tpl.go","sha":"d5f5236e76f98825f082c5d2d125b5f4f0376f09"}]},{"name":"go.mod","path":"codegen/go.mod","sha":"10fc12445001ccc8061886f383e9a37ef704121f"},{"name":"go.sum","path":"codegen/go.sum","sha":"97ba22fb6efe9026c2d23c80a4f90099a2a7b4a1"},{"name":"logging","children":[{"name":"logging.go","path":"codegen/logging/logging.go","sha":"d4fb9da710acb21567b4e0581cb7bd7692baca04"}]}]},{"name":"examples","children":[{"name":"account-baseline-app","children":[{"name":"README.md","path":"examples/account-baseline-app/README.md","sha":"a7925e8838d754d6ffce99821d61cbe6cf1f83df"},{"name":"main.tf","path":"examples/account-baseline-app/main.tf","sha":"620185eb41ec026dfbd2b3f3e70c09577b4438bf"},{"name":"outputs.tf","path":"examples/account-baseline-app/outputs.tf","sha":"99f7a2e4804e904ec545a360df3c85c4248800ae"},{"name":"variables.tf","path":"examples/account-baseline-app/variables.tf","sha":"d4123f5be30364eb594f5d0af7db783f3cbe14b7"}]},{"name":"account-baseline-root","children":[{"name":"README.md","path":"examples/account-baseline-root/README.md","sha":"aa53b9925ab07a760010d174cbf7a671792b137c"},{"name":"main.tf","path":"examples/account-baseline-root/main.tf","sha":"11de8fdb6f504a98bcc8d588bf5806abc3941fb0"},{"name":"outputs.tf","path":"examples/account-baseline-root/outputs.tf","sha":"41480db71946de957e975899635658b6926237d0"},{"name":"variables.tf","path":"examples/account-baseline-root/variables.tf","sha":"5e4f288232b755903abb79ac7cccd8d12a8e3e23"}]},{"name":"account-baseline-security","children":[{"name":"README.md","path":"examples/account-baseline-security/README.md","sha":"292b4ae949b94a126389bd8bf88df5d5ed699649"},{"name":"main.tf","path":"examples/account-baseline-security/main.tf","sha":"98f8da9d73525f61f7aa64012d641bc08cdac208"},{"name":"outputs.tf","path":"examples/account-baseline-security/outputs.tf","sha":"fe0478dd9605f017e38bd084c611c6390bc916d1"},{"name":"variables.tf","path":"examples/account-baseline-security/variables.tf","sha":"ccbec3fe04c7258ce44aab76859925cb7d04e012"}]},{"name":"auto-update","children":[{"name":"README.md","path":"examples/auto-update/README.md","sha":"d7c630c4585bad7869d55bc6c62fca248eeb521a"},{"name":"auto-update-example.json","path":"examples/auto-update/auto-update-example.json","sha":"d122edefdc24b5479a64cb4ffc8d86c773ec322b"}]},{"name":"aws-config-multi-region","children":[{"name":"README.md","path":"examples/aws-config-multi-region/README.md","sha":"5d472db5cdc843b494852a062d8c0880f246fcd0"},{"name":"terraform","children":[{"name":"main.tf","path":"examples/aws-config-multi-region/terraform/main.tf","sha":"344b3e7ee937936e9c4042721ba7ff6a2bb2e68c"},{"name":"outputs.tf","path":"examples/aws-config-multi-region/terraform/outputs.tf","sha":"77ee90f69634c965b8ebed79a8d3afd6adca4db4"},{"name":"variables.tf","path":"examples/aws-config-multi-region/terraform/variables.tf","sha":"28ef8a8f6216d3d717f969f7a74855fdaf789bbc"}]},{"name":"terragrunt","children":[{"name":"terragrunt.hcl","path":"examples/aws-config-multi-region/terragrunt/terragrunt.hcl","sha":"86d8ffdc50802b666497da82ebcaa53cccc550b7"}]}]},{"name":"aws-config-rules","children":[{"name":"README.md","path":"examples/aws-config-rules/README.md","sha":"6cd2794e82af1e3c3620d8feaed136af5358207e"},{"name":"main.tf","path":"examples/aws-config-rules/main.tf","sha":"cedc9cb3bfecfa8ba424fb8fa72bd39852f60119"},{"name":"outputs.tf","path":"examples/aws-config-rules/outputs.tf","sha":"4319400eb4190f58458f2dd9398225869ff08da3"},{"name":"variables.tf","path":"examples/aws-config-rules/variables.tf","sha":"c4b8d3456a3cb94b2d9067a5b7effaf8caa0579b"}]},{"name":"aws-config","children":[{"name":"README.md","path":"examples/aws-config/README.md","sha":"5d66d09633de365e154669a090edc37fc70548d1"},{"name":"main.tf","path":"examples/aws-config/main.tf","sha":"342eba11058e03e469ddc6690b93c85ba1455009"},{"name":"outputs.tf","path":"examples/aws-config/outputs.tf","sha":"ddd32698f39772d663a2d9b8a6276260f5431068"},{"name":"variables.tf","path":"examples/aws-config/variables.tf","sha":"66f62d7333d5df8b562e6f2dfa4f701b88e4f31b"}]},{"name":"aws-organizations","children":[{"name":"README.md","path":"examples/aws-organizations/README.md","sha":"1da3c2fc061fee6ee99564b8b2323ccf69f2c690"},{"name":"main.tf","path":"examples/aws-organizations/main.tf","sha":"cd9b30c06e3919333b5221633f128f352a8e8590"},{"name":"outputs.tf","path":"examples/aws-organizations/outputs.tf","sha":"a713386520ca735201acfc9a560eda7fcf2aa51a"},{"name":"variables.tf","path":"examples/aws-organizations/variables.tf","sha":"59afc28c87bc3c49d11c6faf7e112643f0a95481"}]},{"name":"cloudtrail-custom-key","children":[{"name":"README.md","path":"examples/cloudtrail-custom-key/README.md","sha":"bb376ddaca4b52bef18a5526aa9cb0465574ff7e"},{"name":"main.tf","path":"examples/cloudtrail-custom-key/main.tf","sha":"e965b47e07c72d106875f4d0017e2e7a57f2686d"},{"name":"outputs.tf","path":"examples/cloudtrail-custom-key/outputs.tf","sha":"b6cd4e77d231018a5beb19cd3a9a4eb3f2017d64"},{"name":"variables.tf","path":"examples/cloudtrail-custom-key/variables.tf","sha":"2a2dbf3f59b98262ec8875d8620e2caffbb4b4a0"}]},{"name":"cloudtrail","children":[{"name":"README.md","path":"examples/cloudtrail/README.md","sha":"2fbe4b7494d970738d054910d86d0ae31718c8ec"},{"name":"main.tf","path":"examples/cloudtrail/main.tf","sha":"d605f08945ef52cfd9626315e266fe83c966bfca"},{"name":"outputs.tf","path":"examples/cloudtrail/outputs.tf","sha":"b6cd4e77d231018a5beb19cd3a9a4eb3f2017d64"},{"name":"variables.tf","path":"examples/cloudtrail/variables.tf","sha":"15e36b8b547b6e9b2cd3fdfbaa418ed480b28f37"}]},{"name":"cross-account-iam-roles","children":[{"name":"README.md","path":"examples/cross-account-iam-roles/README.md","sha":"bac6fd37f7f7009454a66e55e8ff377fff36aefb"},{"name":"main.tf","path":"examples/cross-account-iam-roles/main.tf","sha":"38030606b9d68287e287f0fda76512144e52e239"},{"name":"outputs.tf","path":"examples/cross-account-iam-roles/outputs.tf","sha":"44af3be56d0a80e4d509fcd62c0e6dd8628072fa"},{"name":"variables.tf","path":"examples/cross-account-iam-roles/variables.tf","sha":"ae71d83df1715782bb47a965435e3783b7dcee81"}]},{"name":"custom-iam-entity","children":[{"name":"README.md","path":"examples/custom-iam-entity/README.md","sha":"7e6c2e15f44a4ddc28ef276da4b323d2fd326a3f"},{"name":"main.tf","path":"examples/custom-iam-entity/main.tf","sha":"30484f95c30d251fd511957d48b0554d593770aa"},{"name":"outputs.tf","path":"examples/custom-iam-entity/outputs.tf","sha":"835eb64f431386925438cb2f63e48e413faee90c"},{"name":"variables.tf","path":"examples/custom-iam-entity/variables.tf","sha":"d22adf49a09d0d02315679d6d7836a60583775f7"}]},{"name":"ebs-encryption-multi-region","children":[{"name":"README.md","path":"examples/ebs-encryption-multi-region/README.md","sha":"33f8f3f132f3971949a6e8b2d26cabbeb13414b3"},{"name":"main.tf","path":"examples/ebs-encryption-multi-region/main.tf","sha":"dcf504e6f2eaead34885e2e6aa6f69addd9c2113"},{"name":"outputs.tf","path":"examples/ebs-encryption-multi-region/outputs.tf","sha":"49520778a1fc9e5e82777cbb5aa0250e032e1817"},{"name":"variables.tf","path":"examples/ebs-encryption-multi-region/variables.tf","sha":"0f46580369fed2a02ce0152169a7f4d1f4b24254"}]},{"name":"fail2ban","children":[{"name":"README.md","path":"examples/fail2ban/README.md","sha":"6599f8481a3e7666ffe7924707c89b0701d57689"},{"name":"fail2ban-example.json","path":"examples/fail2ban/fail2ban-example.json","sha":"daada12486dceabfd104a98185631dbde4fd791e"},{"name":"main.tf","path":"examples/fail2ban/main.tf","sha":"d694aa99d904517f2af611c29ee0dddc49df974b"},{"name":"outputs.tf","path":"examples/fail2ban/outputs.tf","sha":"77a6ab8a992cd106de126f24b2950c1efa499229"},{"name":"user-data","children":[{"name":"user-data.sh","path":"examples/fail2ban/user-data/user-data.sh","sha":"460b230fb025451e06e8cdd73f83bb5bfea21110"}]},{"name":"variables.tf","path":"examples/fail2ban/variables.tf","sha":"236006c79b34f4fe3a517dd2ae8b805bfb19b6df"}]},{"name":"guardduty","children":[{"name":"README.md","path":"examples/guardduty/README.md","sha":"23c75950a1b8b33286b79bd5e9d853cee02d62ea"},{"name":"main.tf","path":"examples/guardduty/main.tf","sha":"66f22ec901dde1f24ceb334dcf8072d2fc3b3c6d"},{"name":"outputs.tf","path":"examples/guardduty/outputs.tf","sha":"24b4eecc8136725bafa182f1c4febdf90da49a92"},{"name":"variables.tf","path":"examples/guardduty/variables.tf","sha":"77f3fbbeef3500c93b55899ad8e92f44420858ee"}]},{"name":"iam-access-analyzer-multi-region","children":[{"name":"README.md","path":"examples/iam-access-analyzer-multi-region/README.md","sha":"51c398bec469b1d95f4e59e2fb1f287fe621bf20"},{"name":"main.tf","path":"examples/iam-access-analyzer-multi-region/main.tf","sha":"f35638031b879a44e846b3cab009c6517ff3f631"},{"name":"variables.tf","path":"examples/iam-access-analyzer-multi-region/variables.tf","sha":"4f95d4b0726d24d8cc7afd7504c862fb6c4b47a6"}]},{"name":"iam-groups","children":[{"name":"README.md","path":"examples/iam-groups/README.md","sha":"7bd21c82fd8f28f7b3155497a0524d86ce17cfdd"},{"name":"main.tf","path":"examples/iam-groups/main.tf","sha":"bbda4729a441416bdb64ddd14961887aac48f158"},{"name":"outputs.tf","path":"examples/iam-groups/outputs.tf","sha":"5076c13be431d7844e1ce524bcd40076450c051e"},{"name":"variables.tf","path":"examples/iam-groups/variables.tf","sha":"6132b953e392a2050532881faab88a2eb10378c6"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"examples/iam-user-password-policy/README.md","sha":"bc62258833767d2e383a130c43d57a11e229af27"},{"name":"main.tf","path":"examples/iam-user-password-policy/main.tf","sha":"bc51ae2d849554f3b23222b6f97e04bc8e382470"},{"name":"variables.tf","path":"examples/iam-user-password-policy/variables.tf","sha":"e123f5bbbaa376c3c8edf5f37e2bc012feed65d7"}]},{"name":"iam-users","children":[{"name":"README.md","path":"examples/iam-users/README.md","sha":"f8b65e9756e9f8c8703a854c1363be700b5fe8d9"},{"name":"main.tf","path":"examples/iam-users/main.tf","sha":"b6b94036a7042321515bb106d00c098d2f317278"},{"name":"outputs.tf","path":"examples/iam-users/outputs.tf","sha":"2b305a310e6c78ed5d89ff62303b5c64b956bd12"},{"name":"variables.tf","path":"examples/iam-users/variables.tf","sha":"d3693a709d6bee6f57aabaf07cddb0f02349c7a4"}]},{"name":"ip-lockdown","children":[{"name":"README.md","path":"examples/ip-lockdown/README.md","sha":"3962ba23a76d8f02e5c0ffc8cb71196991628e38"},{"name":"aws-example","children":[{"name":"README.md","path":"examples/ip-lockdown/aws-example/README.md","sha":"da44a1265bdd321d10b4a6e3471a655da91033bb"},{"name":"main.tf","path":"examples/ip-lockdown/aws-example/main.tf","sha":"0568d5a2922ebcb3208dbd52d34dec4169aca917"},{"name":"outputs.tf","path":"examples/ip-lockdown/aws-example/outputs.tf","sha":"a175a78c9a10f9f2fd9d7c84f9b304aebc1bdb41"},{"name":"user-data","children":[{"name":"user-data.sh","path":"examples/ip-lockdown/aws-example/user-data/user-data.sh","sha":"c6d308027737a434f4c96bc3eba5bd301897af62"}]},{"name":"variables.tf","path":"examples/ip-lockdown/aws-example/variables.tf","sha":"85be46b79dfe349e32974eccdc9c3206211787ac"}]},{"name":"ip-lockdown-sample.json","path":"examples/ip-lockdown/ip-lockdown-sample.json","sha":"30757f525fcfe3c1fd3ea080d1e3077519245c56"},{"name":"local-test","children":[{"name":"README.md","path":"examples/ip-lockdown/local-test/README.md","sha":"3f0e1a6483ce3155bb04dbb9a4fd76ed41486d35"},{"name":"docker-compose.yml","path":"examples/ip-lockdown/local-test/docker-compose.yml","sha":"7c8e3a5d1fd40a95ef99b4bba0911c63ed43b530"}]}]},{"name":"kms-grant-multi-region","children":[{"name":"main.tf","path":"examples/kms-grant-multi-region/main.tf","sha":"b8bffbf620d0c359145177b7d7e5a79622cfb970"},{"name":"variables.tf","path":"examples/kms-grant-multi-region/variables.tf","sha":"43e0dc3512d054801c09cd80e47fb28b13f249a7"}]},{"name":"kms-master-key-multi-region","children":[{"name":"main.tf","path":"examples/kms-master-key-multi-region/main.tf","sha":"287980a9b31c91156dc1d7d3cd90321432d215c8"},{"name":"outputs.tf","path":"examples/kms-master-key-multi-region/outputs.tf","sha":"c2685a282b5ce295c2dd80a78841711a40e80dcb"},{"name":"variables.tf","path":"examples/kms-master-key-multi-region/variables.tf","sha":"00812e35b344a3d0a715bb781b606627dda87045"}]},{"name":"kms-master-key","children":[{"name":"README.md","path":"examples/kms-master-key/README.md","sha":"821565d831f2afcf7a2ffeea9a0854fabdaae033"},{"name":"main.tf","path":"examples/kms-master-key/main.tf","sha":"fe52cb44fa782e6a5db7abf0f65a97e8c13b4f4a"},{"name":"outputs.tf","path":"examples/kms-master-key/outputs.tf","sha":"4d5fd0a19ea917beff0241f169b51417ff9935b9"},{"name":"variables.tf","path":"examples/kms-master-key/variables.tf","sha":"c1de5a7b1c0859710d1253b61baf86c4564560e3"}]},{"name":"ntp","children":[{"name":"README.md","path":"examples/ntp/README.md","sha":"b676e802c1d196f6af204d14d143b80864bccd30"},{"name":"ntp-example.json","path":"examples/ntp/ntp-example.json","sha":"98536345621a250d03957280a97f06ad1a465bcd"}]},{"name":"os-hardening","children":[{"name":"README.md","path":"examples/os-hardening/README.md","sha":"d311d0932f7e98b236d0dcf3d9c629a7f8b3b107"},{"name":"packer-build.sh","path":"examples/os-hardening/packer-build.sh","sha":"8a0cf99893046f648c04ad62d505746e9c3a5e95"},{"name":"packer","children":[{"name":"amazon-linux.json","path":"examples/os-hardening/packer/amazon-linux.json","sha":"35287d613dd1b136a4a0cbfd658b2b4979ee152b"},{"name":"files","children":[{"name":"etc","children":[{"name":"fstab","path":"examples/os-hardening/packer/files/etc/fstab","sha":"cbf68cec68a92bc54f514dd0d6906f19cea857e6"}]}]}]},{"name":"terraform","children":[{"name":"main.tf","path":"examples/os-hardening/terraform/main.tf","sha":"a5a8fc407a33edac4e8182fb65ece62f30ada9b0"},{"name":"outputs.tf","path":"examples/os-hardening/terraform/outputs.tf","sha":"33083aed25a4ed6e323bf84381b896614814c9d1"},{"name":"variables.tf","path":"examples/os-hardening/terraform/variables.tf","sha":"25d9e4a3ecf236434b71fd2eac179fa27cdb8587"}]}]},{"name":"private-s3-bucket","children":[{"name":"README.md","path":"examples/private-s3-bucket/README.md","sha":"5214e6225de5e051cb2842fa2eb6e04a92184a10"},{"name":"main.tf","path":"examples/private-s3-bucket/main.tf","sha":"84091d1931525fbe14461dbad20d3997d68952e8"},{"name":"outputs.tf","path":"examples/private-s3-bucket/outputs.tf","sha":"efddeeb33901e91f4f28a438afb3455f2cca5e18"},{"name":"variables.tf","path":"examples/private-s3-bucket/variables.tf","sha":"92ff2336e37bd84902a59213bfe370c2f2ae9eac"}]},{"name":"saml-iam-roles","children":[{"name":"README.md","path":"examples/saml-iam-roles/README.md","sha":"b4ef2b28d5704aec892ea54cc28a61fbb46378c9"},{"name":"main.tf","path":"examples/saml-iam-roles/main.tf","sha":"4f90112b343ad9ca982483f1a055182596780483"},{"name":"outputs.tf","path":"examples/saml-iam-roles/outputs.tf","sha":"1bd4fec9529cddfd2d3f61bba60f9dfb8b286c70"},{"name":"saml-metadata.xml","path":"examples/saml-iam-roles/saml-metadata.xml","sha":"88596cfde52242a43559c79216a1c60b2ea12903"},{"name":"variables.tf","path":"examples/saml-iam-roles/variables.tf","sha":"28705aa859940aa4b8027a19fe0b5b4affba939e"}]},{"name":"secrets-manager-resource-policies","children":[{"name":"README.md","path":"examples/secrets-manager-resource-policies/README.md","sha":"289a83c28bd9142fc7bbb4e603a4b25b4c9c1b98"},{"name":"main.tf","path":"examples/secrets-manager-resource-policies/main.tf","sha":"ec0592778bb88d6670c78b2f246489449e12ca7c"},{"name":"variables.tf","path":"examples/secrets-manager-resource-policies/variables.tf","sha":"d6f5c45fbc2173475cec7c4e77ac8f5caed4dc27"}]},{"name":"ssh-grunt","children":[{"name":"iam","children":[{"name":"README.md","path":"examples/ssh-grunt/iam/README.md","sha":"6fea994ce030780787df5ebbcaf9c93d52c3ca89"},{"name":"main.tf","path":"examples/ssh-grunt/iam/main.tf","sha":"cfcdbff073823dd30c4c544079b63ef17906abbc"},{"name":"outputs.tf","path":"examples/ssh-grunt/iam/outputs.tf","sha":"978b316044d417393b70100a427de1068c4d417f"},{"name":"variables.tf","path":"examples/ssh-grunt/iam/variables.tf","sha":"1ee58afdef7dad43bb3fb221995cc3daf631177b"}]},{"name":"packer","children":[{"name":"README.md","path":"examples/ssh-grunt/packer/README.md","sha":"48c0a14517132c2c05fdc15496fa1bcd777c38d4"},{"name":"build-binary.sh","path":"examples/ssh-grunt/packer/build-binary.sh","sha":"fe84ead78eb3e87e4855272f28c83d681c58ffff"},{"name":"ssh-grunt-iam.json","path":"examples/ssh-grunt/packer/ssh-grunt-iam.json","sha":"e840f011e27a5525d55eaab66bb0cf87a9a8d88e"}]}]},{"name":"ssm-healthchecks-iam-permissions","children":[{"name":"README.md","path":"examples/ssm-healthchecks-iam-permissions/README.md","sha":"f1fe555a3aff887a966def0a1d3ccaff3dd826e7"},{"name":"main.tf","path":"examples/ssm-healthchecks-iam-permissions/main.tf","sha":"18efa7bf3861cff68c700470347ed3808b00fb8c"},{"name":"outputs.tf","path":"examples/ssm-healthchecks-iam-permissions/outputs.tf","sha":"52688c3a4f1f8349500505fb8949fa0d21c385a3"},{"name":"variables.tf","path":"examples/ssm-healthchecks-iam-permissions/variables.tf","sha":"725532cff7e91c2858c666a8d6a21cade2db213c"}]}]},{"name":"modules","children":[{"name":"_deprecated","children":[{"name":"custom-iam-group","children":[{"name":"README.md","path":"modules/_deprecated/custom-iam-group/README.md","sha":"e7a0ff783eb1052aa77fe50d7eaa6a06d2d82649"}]}]},{"name":"account-baseline-app","children":[{"name":"README.adoc","path":"modules/account-baseline-app/README.adoc","sha":"d2ea8862241a6be11fb39098768eeedfcee05ea7"},{"name":"main.tf","path":"modules/account-baseline-app/main.tf","sha":"49d7e0bc21c6fc3cb8a52f74f2b9e5319406d8a0"},{"name":"outputs.tf","path":"modules/account-baseline-app/outputs.tf","sha":"9ed4786bacd935c1b2ebf44973f00a790fa3a548"},{"name":"variables.tf","path":"modules/account-baseline-app/variables.tf","sha":"7cd54db7c63aa2c14cf0291057776b22b6aeab6c"}]},{"name":"account-baseline-root","children":[{"name":"README.adoc","path":"modules/account-baseline-root/README.adoc","sha":"ed158ce608bc26d37a14e49266948f2194b4368f"},{"name":"core-concepts.md","path":"modules/account-baseline-root/core-concepts.md","sha":"591d2687e4d787b998598e2200def022f6915aec"},{"name":"logs-account-resources.tf","path":"modules/account-baseline-root/logs-account-resources.tf","sha":"81e983c24272a29d4c0065c87b80cd339b239c59"},{"name":"main.tf","path":"modules/account-baseline-root/main.tf","sha":"66d638a38a5475909d2b3ba20f670cfca27d09cf"},{"name":"outputs.tf","path":"modules/account-baseline-root/outputs.tf","sha":"fdb502cdc0b1f848c250fd2696522cfce65e64a9"},{"name":"variables.tf","path":"modules/account-baseline-root/variables.tf","sha":"b6c5335683423ac87d00d46444d4d731372f550b"}]},{"name":"account-baseline-security","children":[{"name":"README.adoc","path":"modules/account-baseline-security/README.adoc","sha":"4a6ff36ad488396075f61c9e8c01ef16d2d4656d"},{"name":"main.tf","path":"modules/account-baseline-security/main.tf","sha":"28adf875ba61821353f4bc04a99f36b0e5c7182b"},{"name":"outputs.tf","path":"modules/account-baseline-security/outputs.tf","sha":"42cf8f91e8cdd0543f4068bdeb6b79d74bdbd96b"},{"name":"variables.tf","path":"modules/account-baseline-security/variables.tf","sha":"a2a40a85554f70627563496460c8559562b5daf1"}]},{"name":"auto-update","children":[{"name":"README.adoc","path":"modules/auto-update/README.adoc","sha":"516a59291374a849ba3183cac9263bcfe90f8bfe"},{"name":"core-concepts.md","path":"modules/auto-update/core-concepts.md","sha":"0e4dd35dc4b7320764f203b5cc91e55ecaa9b0be"},{"name":"install-scripts","children":[{"name":"configure-auto-update","path":"modules/auto-update/install-scripts/configure-auto-update","sha":"9557efec90bf62cbcd0360198ec2bf984a8a873b"},{"name":"unattended_upgrades_config.txt","path":"modules/auto-update/install-scripts/unattended_upgrades_config.txt","sha":"abe88fd8a5037ce518bec69a6cac0699cb421d47"},{"name":"yum_cron_config.txt","path":"modules/auto-update/install-scripts/yum_cron_config.txt","sha":"e7ef4273f1b2af0c9c032fadaacd03130ba5ea78"}]},{"name":"install.sh","path":"modules/auto-update/install.sh","sha":"7c19fd0d04b11c358af64149b3169d6b2c5e3b58"}]},{"name":"aws-auth","children":[{"name":"AWS-AUTH-1PASSWORD.md","path":"modules/aws-auth/AWS-AUTH-1PASSWORD.md","sha":"bcfd06153c8ee21f1e3468ce9b1634d5dc7cc68c"},{"name":"AWS-AUTH-LASTPASS.md","path":"modules/aws-auth/AWS-AUTH-LASTPASS.md","sha":"7c370864041284d8ce90749c0bc5dca744c43a5a"},{"name":"README.md","path":"modules/aws-auth/README.md","sha":"c0c0cc6643d546871d18d5bf9ca7948bf9b13407"},{"name":"bin","children":[{"name":"aws-auth","path":"modules/aws-auth/bin/aws-auth","sha":"53ac944b29b7f15d97d312b0fd3745ffbd0a6dd8"}]},{"name":"install.sh","path":"modules/aws-auth/install.sh","sha":"ab9611d92d6822ceed981bdff3766724366037f0"}]},{"name":"aws-config-bucket","children":[{"name":"README.md","path":"modules/aws-config-bucket/README.md","sha":"2988d934e16617289522a4ea711ee07589ce96d7"},{"name":"main.tf","path":"modules/aws-config-bucket/main.tf","sha":"cd688997e2084dd18493b23bf7be03192fff2bda"},{"name":"outputs.tf","path":"modules/aws-config-bucket/outputs.tf","sha":"8ac7ab1c4c5ded586bee63ce460b25cd60eb4a18"},{"name":"variables.tf","path":"modules/aws-config-bucket/variables.tf","sha":"a4a360e78df5c7dc310e7dcd5dba952af109e7c9"}]},{"name":"aws-config-multi-region","children":[{"name":"README.adoc","path":"modules/aws-config-multi-region/README.adoc","sha":"fb308d4303343786cde18f5f830e313c13800c5c"},{"name":"core-concepts.md","path":"modules/aws-config-multi-region/core-concepts.md","sha":"976e6424dcb277f70377f92eb2a10d0c8e595a85"},{"name":"main.tf","path":"modules/aws-config-multi-region/main.tf","sha":"a1f88046952d794aa9fb6744eacbf52a51cbba00"},{"name":"outputs.tf","path":"modules/aws-config-multi-region/outputs.tf","sha":"b0b62c8a003fcef88734cb540ad9e75b25721ffa"},{"name":"variables.tf","path":"modules/aws-config-multi-region/variables.tf","sha":"86f014396e15600dfd6e2772ef018539eaca55ae"}]},{"name":"aws-config-rules","children":[{"name":"README.adoc","path":"modules/aws-config-rules/README.adoc","sha":"ca94303a3431a36423729737e618799efc8bd2e5"},{"name":"core-concepts.md","path":"modules/aws-config-rules/core-concepts.md","sha":"10477be51fde642f31032ccd15a55d9218eff224"},{"name":"main.tf","path":"modules/aws-config-rules/main.tf","sha":"586df8b5f809a8b64d98a4fedce578b53096bcbe"},{"name":"outputs.tf","path":"modules/aws-config-rules/outputs.tf","sha":"c297ad118d46f79f286d6577770ab46e59555ccb"},{"name":"variables.tf","path":"modules/aws-config-rules/variables.tf","sha":"d2b203f62960cb08d9f84c506067facaa1a2d451"}]},{"name":"aws-config","children":[{"name":"README.adoc","path":"modules/aws-config/README.adoc","sha":"4c96ef84a47bcba1feb7814773219586cbaef9c8"},{"name":"core-concepts.md","path":"modules/aws-config/core-concepts.md","sha":"e5a7b8646bab42398ff7f5224549e528ce8c0d52"},{"name":"main.tf","path":"modules/aws-config/main.tf","sha":"ff74c507a78850cfce82b886b7bf6a0aaa01e30a"},{"name":"outputs.tf","path":"modules/aws-config/outputs.tf","sha":"bcd505e4ac4102bc09750adb36c99398a06eb1a6"},{"name":"variables.tf","path":"modules/aws-config/variables.tf","sha":"9be6915fc2de8103550ae4cbf24eb8908eff6148"}]},{"name":"aws-organizations","children":[{"name":"README.adoc","path":"modules/aws-organizations/README.adoc","sha":"0eaaffc3130fe20acbde5c94ddb6025d24dc6eb1"},{"name":"core-concepts.md","path":"modules/aws-organizations/core-concepts.md","sha":"8766c8f36eef9e8992bf13a44f6571261c43995d"},{"name":"main.tf","path":"modules/aws-organizations/main.tf","sha":"74efb23a04f4cabac266dc859421a66bee7d0041"},{"name":"outputs.tf","path":"modules/aws-organizations/outputs.tf","sha":"feed57b33ab7eb9b100712647942f1a8d7245b3d"},{"name":"variables.tf","path":"modules/aws-organizations/variables.tf","sha":"4eac97565d5ab76a5e0c03cde4a9337001125156"}]},{"name":"cloudtrail-bucket","children":[{"name":"README.md","path":"modules/cloudtrail-bucket/README.md","sha":"77bdc9e5689c0c06503867153355bc81d9962498"},{"name":"main.tf","path":"modules/cloudtrail-bucket/main.tf","sha":"1c9c65cb383e142a0626adde014643c119517f49"},{"name":"outputs.tf","path":"modules/cloudtrail-bucket/outputs.tf","sha":"1e560e9b0cc1c8f40e81d5fe8bbbf1c03258fdae"},{"name":"variables.tf","path":"modules/cloudtrail-bucket/variables.tf","sha":"688a2bfddf44c7a9bf7686ec2fbcc797c40dbe66"}]},{"name":"cloudtrail","children":[{"name":"README.adoc","path":"modules/cloudtrail/README.adoc","sha":"311a18daf574481f91e609b6c91803e1cd23a33e"},{"name":"core-concepts.md","path":"modules/cloudtrail/core-concepts.md","sha":"7e8c8a4631410e36831f5ae2b5644d229d36a4d0"},{"name":"main.tf","path":"modules/cloudtrail/main.tf","sha":"026fb4c157b6a8902efadfc5f9adbc2c2576be58"},{"name":"outputs.tf","path":"modules/cloudtrail/outputs.tf","sha":"d161a32bbcd6f824955c273c49ef9e00bcdb57b3"},{"name":"variables.tf","path":"modules/cloudtrail/variables.tf","sha":"cf6cdf422d9c3af70d82e6ce446c617e8ceb80e5"}]},{"name":"cross-account-iam-roles","children":[{"name":"README.md","path":"modules/cross-account-iam-roles/README.md","sha":"47b6fde4186405fd3e4940050f7fc065dc0f9b4f"},{"name":"main.tf","path":"modules/cross-account-iam-roles/main.tf","sha":"15e594530e941271922a65800b01f40c8e3f462d"},{"name":"outputs.tf","path":"modules/cross-account-iam-roles/outputs.tf","sha":"4e4697d3c627fc668206d03557f8d58b3f391465"},{"name":"variables.tf","path":"modules/cross-account-iam-roles/variables.tf","sha":"d03ba0e2e2846b2b34f0ec612e31db7485f23bdc"}]},{"name":"custom-iam-entity","children":[{"name":"README.md","path":"modules/custom-iam-entity/README.md","sha":"7e0ac019931836a663354723e51d922fc30f08ee"},{"name":"main.tf","path":"modules/custom-iam-entity/main.tf","sha":"53fb8239509ccfb285abdd363bc1912cb1cd3357"},{"name":"outputs.tf","path":"modules/custom-iam-entity/outputs.tf","sha":"b94249803e78991682b8542d8f39e5a728432b97"},{"name":"variables.tf","path":"modules/custom-iam-entity/variables.tf","sha":"ad93fc85d6d7c21bb348086a72406f08ccd07edb"}]},{"name":"ebs-encryption-multi-region","children":[{"name":"README.adoc","path":"modules/ebs-encryption-multi-region/README.adoc","sha":"f452559ca803195574f30ae6323f54b58f91aaa3"},{"name":"main.tf","path":"modules/ebs-encryption-multi-region/main.tf","sha":"1d1222b2990247cfc4888ca49dfbace4c053753b"},{"name":"outputs.tf","path":"modules/ebs-encryption-multi-region/outputs.tf","sha":"16baedd2d7e0b29b7c91888bb251956a83d30d7e"},{"name":"variables.tf","path":"modules/ebs-encryption-multi-region/variables.tf","sha":"abe1386cf0824d0d76dd3d01f3f7682e751a0379"}]},{"name":"ebs-encryption","children":[{"name":"README.md","path":"modules/ebs-encryption/README.md","sha":"f9f23a71b7725648a9fdc9300de92d38014e6f63"},{"name":"main.tf","path":"modules/ebs-encryption/main.tf","sha":"9ff5c055961289dbb05767e084a494cb36e4c1a8"},{"name":"outputs.tf","path":"modules/ebs-encryption/outputs.tf","sha":"6caa6eba337ae7aa9ad7db82dbd2cf6223f42cb9"},{"name":"variables.tf","path":"modules/ebs-encryption/variables.tf","sha":"d47c23a0c98c7561fcf0d95fa22fc40b34182bf9"}]},{"name":"fail2ban","children":[{"name":"README.md","path":"modules/fail2ban/README.md","sha":"e4cd7c70b170022b2e306289d4e8b949c58dd6ab"},{"name":"install-scripts","children":[{"name":"cloudwatch-metric.conf","path":"modules/fail2ban/install-scripts/cloudwatch-metric.conf","sha":"b2fb301180aeb253f5168a6fedd3e5c44b6938ff"},{"name":"configure-fail2ban","path":"modules/fail2ban/install-scripts/configure-fail2ban","sha":"63463897dedf4e7272d448395271799c0edf9d69"},{"name":"fail2ban.local","path":"modules/fail2ban/install-scripts/fail2ban.local","sha":"ea80bf8058a1f9bb1a80a59031981b2a37445750"},{"name":"filters.sshd.amazon.conf","path":"modules/fail2ban/install-scripts/filters.sshd.amazon.conf","sha":"093bb1baf88a1e283a43b7dd7d04c64992abecc6"},{"name":"jail.amazon.local","path":"modules/fail2ban/install-scripts/jail.amazon.local","sha":"1284b66ca5a007b77a40c27b66662425e7fe8c91"},{"name":"jail.amazon2.local","path":"modules/fail2ban/install-scripts/jail.amazon2.local","sha":"8f0285c493c406aa0db98f40b8bf9aa238f52353"},{"name":"jail.ubuntu.local","path":"modules/fail2ban/install-scripts/jail.ubuntu.local","sha":"b3485d20a2b1fad7949167d30eff2b4caf357d81"}]},{"name":"install.sh","path":"modules/fail2ban/install.sh","sha":"8f7b536f08506dabc2f6beb6cd5a50f7282168aa"},{"name":"user-data-scripts","children":[{"name":"configure-fail2ban-cloudwatch.sh","path":"modules/fail2ban/user-data-scripts/configure-fail2ban-cloudwatch.sh","sha":"5c112c70c078b769f3ae31e71334499d0e5be64a"}]}]},{"name":"guardduty-multi-region","children":[{"name":"README.adoc","path":"modules/guardduty-multi-region/README.adoc","sha":"ab5259fd33416948231b5d9c4852ac5981b49540"},{"name":"main.tf","path":"modules/guardduty-multi-region/main.tf","sha":"1b990cf6aef7937f06d25030d15dd4b583948e5c"},{"name":"outputs.tf","path":"modules/guardduty-multi-region/outputs.tf","sha":"17ed87f6be722742d29aee0ef8e35a641a2ea54e"},{"name":"variables.tf","path":"modules/guardduty-multi-region/variables.tf","sha":"992199e9e968a3006918b286c7f3e69eb2fbbd74"}]},{"name":"guardduty","children":[{"name":"README.adoc","path":"modules/guardduty/README.adoc","sha":"8826f32664593d0cdc0ff4a7fd94e5cbf475478a"},{"name":"core-concepts.md","path":"modules/guardduty/core-concepts.md","sha":"2eab0fd6c0548ba11104b6d778eb224df5622886"},{"name":"main.tf","path":"modules/guardduty/main.tf","sha":"97879eff4cbd4e4760168586ec567e50c3fbd9cf"},{"name":"outputs.tf","path":"modules/guardduty/outputs.tf","sha":"0fd6fdc76d8bc1bb4c544028c802248999d309f7"},{"name":"variables.tf","path":"modules/guardduty/variables.tf","sha":"e5c1e4b60f219d93e21a382bb3dad970977c9fcf"}]},{"name":"iam-access-analyzer-multi-region","children":[{"name":"README.adoc","path":"modules/iam-access-analyzer-multi-region/README.adoc","sha":"069ee2ac36dc7525a1598ed994b5671ad945b73e"},{"name":"core-concepts.md","path":"modules/iam-access-analyzer-multi-region/core-concepts.md","sha":"6bbaac3d7e62744e3fe3f511cd4ae78b212d08a8"},{"name":"main.tf","path":"modules/iam-access-analyzer-multi-region/main.tf","sha":"13d51ee07145bffe68441c3bce8a420c9efd7ed5"},{"name":"outputs.tf","path":"modules/iam-access-analyzer-multi-region/outputs.tf","sha":"0a4379e38beae72541e7e975f297584db7e98b04"},{"name":"variables.tf","path":"modules/iam-access-analyzer-multi-region/variables.tf","sha":"fe5c514084fbbe9ef542e6b849c37b5c81739cd0"}]},{"name":"iam-groups","children":[{"name":"README.md","path":"modules/iam-groups/README.md","sha":"07820342d38caf90b08a1ff0df904298ed132c8f"},{"name":"_docs","children":[{"name":"iam-user-access-to-billing.png","path":"modules/iam-groups/_docs/iam-user-access-to-billing.png","sha":"063f6cf8dc766b4d44942de89660e8ab9e1f3d63"},{"name":"my-account.png","path":"modules/iam-groups/_docs/my-account.png","sha":"387320200ed756ce4191afef87f0ab76e2c3d89a"}]},{"name":"main.tf","path":"modules/iam-groups/main.tf","sha":"f9e835e2d02b99a8713df49dc0daa4d36be5dd9d"},{"name":"outputs.tf","path":"modules/iam-groups/outputs.tf","sha":"0fc97269b51e6c51647aa5420198d1d11c5afa37"},{"name":"variables.tf","path":"modules/iam-groups/variables.tf","sha":"d54e229b070925f1c927090781333c20ae6d765f"}]},{"name":"iam-policies","children":[{"name":"README.md","path":"modules/iam-policies/README.md","sha":"0297e14a7dfdf5727d9be5ab4f47dcf67357b247"},{"name":"main.tf","path":"modules/iam-policies/main.tf","sha":"650bb81bc89e03b1f86de74e010c4454d2a5e146"},{"name":"outputs.tf","path":"modules/iam-policies/outputs.tf","sha":"19511cfc28b22103cb164c6df8b5b530e7e3e172"},{"name":"variables.tf","path":"modules/iam-policies/variables.tf","sha":"02a3add807a7878bc736a0a1aaa193ac42ee5b47"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"modules/iam-user-password-policy/README.md","sha":"5bea6ba56fc796be5b860549156a3a251735fc2a"},{"name":"main.tf","path":"modules/iam-user-password-policy/main.tf","sha":"00372963f07a36d47ec3fc3489ab2446bd16893c"},{"name":"variables.tf","path":"modules/iam-user-password-policy/variables.tf","sha":"7c08eef88a7b13226cc4e18aa8338db64fdf83f0"}]},{"name":"iam-users","children":[{"name":"README.md","path":"modules/iam-users/README.md","sha":"eacb8c8dd745d047f3844e0b63573af66b8c1083"},{"name":"main.tf","path":"modules/iam-users/main.tf","sha":"ce5f9dc0a4b152d1b48b66b387f57e1678258229"},{"name":"outputs.tf","path":"modules/iam-users/outputs.tf","sha":"4d053caccca2412befcf956c94e908b2d5c89054"},{"name":"variables.tf","path":"modules/iam-users/variables.tf","sha":"25e55a291fa64e63996f5baab05a2082b548cd41"}]},{"name":"ip-lockdown","children":[{"name":"README.md","path":"modules/ip-lockdown/README.md","sha":"7ec92da38b5b06af9e61ab164bb6b4b0470ed92a"},{"name":"install.sh","path":"modules/ip-lockdown/install.sh","sha":"ce61af763bee9ad29754220ae24521f22c3a956f"},{"name":"ip-lockdown","path":"modules/ip-lockdown/ip-lockdown","sha":"93a0e1f5876e7de5778c595e8801d64986cb118b"}]},{"name":"kms-grant-multi-region","children":[{"name":"README.adoc","path":"modules/kms-grant-multi-region/README.adoc","sha":"fea6fb06a33f23861f1660b49d1bbafa63e92c48"},{"name":"core-concepts.md","path":"modules/kms-grant-multi-region/core-concepts.md","sha":"3eb1725fa927a84cc2a0341335d150bf5c6e70f5"},{"name":"main.tf","path":"modules/kms-grant-multi-region/main.tf","sha":"ad8d4c0f45431fb071e3dbf1a6b45ac0c500b903"},{"name":"outputs.tf","path":"modules/kms-grant-multi-region/outputs.tf","sha":"b9d84078afacb154536292bddba4afbd6c9158c2"},{"name":"variables.tf","path":"modules/kms-grant-multi-region/variables.tf","sha":"d27a8da6b13e1ea67a1b4721edd8bbe59781df7d"}]},{"name":"kms-master-key-multi-region","children":[{"name":"README.adoc","path":"modules/kms-master-key-multi-region/README.adoc","sha":"73f3c01b25a01bda21f3ea98c28a54c3b8b3ab89"},{"name":"main.tf","path":"modules/kms-master-key-multi-region/main.tf","sha":"b26c2077c9db8e93f20cac4e822591df0c75bd53"},{"name":"outputs.tf","path":"modules/kms-master-key-multi-region/outputs.tf","sha":"932a3ac2a94e4950267c55c115f1118328345bf3"},{"name":"variables.tf","path":"modules/kms-master-key-multi-region/variables.tf","sha":"f97ad1ca562b31afbddfb35aebb5cb1f772191c9"}]},{"name":"kms-master-key","children":[{"name":"README.md","path":"modules/kms-master-key/README.md","sha":"1b43a005494f12b05551adb020a31726f28e10d3"},{"name":"main.tf","path":"modules/kms-master-key/main.tf","sha":"141f65f6938a5507a0219f48abb2dec0d79ccdd1"},{"name":"outputs.tf","path":"modules/kms-master-key/outputs.tf","sha":"4d0dbba81e8186243d96a8325a5f643d87543451"},{"name":"variables.tf","path":"modules/kms-master-key/variables.tf","sha":"4b4f49c17034d827f23175cbb712ff757ae7c34f"}]},{"name":"ntp","children":[{"name":"README.md","path":"modules/ntp/README.md","sha":"31112a11cff027ba074d454f5a23c5ce3e839c11"},{"name":"install.sh","path":"modules/ntp/install.sh","sha":"66f01538550459e770dde3d03b8c1ee705301b49"}]},{"name":"os-hardening","children":[{"name":"README.md","path":"modules/os-hardening/README.md","sha":"3e864b0e9208eb6809adf41968c51e02fc233ee1"},{"name":"_docs","children":[{"name":"Helpful Email.md","path":"modules/os-hardening/_docs/Helpful Email.md","sha":"246a0b80b29f5ff3d2b2f4c5c170fc927e2d9dd7"}]},{"name":"ami-builder","children":[{"name":"files","children":[{"name":"user-data.sh.template","path":"modules/os-hardening/ami-builder/files/user-data.sh.template","sha":"4a3c87a19e1a4caa20b9b425b2a02101566d1166"}]},{"name":"main.tf","path":"modules/os-hardening/ami-builder/main.tf","sha":"3561bfae1f5988023e825667e73cb835caa3df79"},{"name":"outputs.tf","path":"modules/os-hardening/ami-builder/outputs.tf","sha":"8ce2ee598124ca50dd530a33aa60f5d1452a4a2b"},{"name":"variables.tf","path":"modules/os-hardening/ami-builder/variables.tf","sha":"d760f34eeae322790865c1cb30dfe20d0225328f"}]},{"name":"partition-scripts","children":[{"name":"README.md","path":"modules/os-hardening/partition-scripts/README.md","sha":"b55df29c7a3d6dc3ecbbbfe4ab4b8749f053f00b"},{"name":"bin","children":[{"name":"cleanup-volume","path":"modules/os-hardening/partition-scripts/bin/cleanup-volume","sha":"c7cbf3ecebd915235238557d27a1ce25e6fc10fa"},{"name":"partition-volume","path":"modules/os-hardening/partition-scripts/bin/partition-volume","sha":"f4f8566a1ef6aa4ff0c0268bd28721488aa6dfc4"}]},{"name":"install.sh","path":"modules/os-hardening/partition-scripts/install.sh","sha":"606776c068260836e8612a681ff4e3edc8abdb41"}]}]},{"name":"private-s3-bucket","children":[{"name":"README.md","path":"modules/private-s3-bucket/README.md","sha":"36f7267d282623839f794ddebbe861ef74f56e13"},{"name":"main.tf","path":"modules/private-s3-bucket/main.tf","sha":"5c45bbe4babd9e69d4e02575e0529eb9965fab3b"},{"name":"outputs.tf","path":"modules/private-s3-bucket/outputs.tf","sha":"f2ab2237674b888d45bbede9f9b6f0dafe7471ea"},{"name":"variables.tf","path":"modules/private-s3-bucket/variables.tf","sha":"5e96f2e68b5b9d4d3ccc22b9518265209ccc5373"}]},{"name":"saml-iam-roles","children":[{"name":"README.md","path":"modules/saml-iam-roles/README.md","sha":"5ebc8c20f781a0f0b5654decdcf9bd607fee65b3"},{"name":"main.tf","path":"modules/saml-iam-roles/main.tf","sha":"23bf01a0f85e31040aac200e3d8fe560fcb537b6"},{"name":"outputs.tf","path":"modules/saml-iam-roles/outputs.tf","sha":"c579901907b216c55e4c815d28f0a22171a960e6"},{"name":"variables.tf","path":"modules/saml-iam-roles/variables.tf","sha":"1f3f26ade9fd75d8e66ba12649f45d075b5e0f2b"}]},{"name":"secrets-manager-resource-policies","children":[{"name":"README.md","path":"modules/secrets-manager-resource-policies/README.md","sha":"b894ce3171c28ae91acbfe6bdcec35615c599bbb"},{"name":"main.tf","path":"modules/secrets-manager-resource-policies/main.tf","sha":"9b316776ed662cc85290568a2c3dfa94785b21f4"},{"name":"outputs.tf","path":"modules/secrets-manager-resource-policies/outputs.tf","sha":"8b237f325d54b84ac2453e8945f61cdf0d24b41b"},{"name":"variables.tf","path":"modules/secrets-manager-resource-policies/variables.tf","sha":"2b45ef099c805c1265e5dc611c138de4a40141eb"}]},{"name":"ssh-grunt-selinux-policy","children":[{"name":"README.md","path":"modules/ssh-grunt-selinux-policy/README.md","sha":"53f02f57185efebc35d6ebfe156ce73d02a5f112"},{"name":"install.sh","path":"modules/ssh-grunt-selinux-policy/install.sh","sha":"3de871d61a9990e7f2c130f23afaf00daeb6bbef"},{"name":"ssh-grunt.pp","path":"modules/ssh-grunt-selinux-policy/ssh-grunt.pp","sha":"7c7050f812cd0e3cb34e37b88c35fb09f369be7d"},{"name":"ssh-grunt.te","path":"modules/ssh-grunt-selinux-policy/ssh-grunt.te","sha":"3317a71feaa633662a00b1dc05b1176cb85c9793"}]},{"name":"ssh-grunt","children":[{"name":".dockerignore","path":"modules/ssh-grunt/.dockerignore","sha":"a725465aee245635a2bd129af54858ed32c84cb8"},{"name":"Dockerfile","path":"modules/ssh-grunt/Dockerfile","sha":"95acbc9a8a04bf1e5dcf7ef92578bbbdc3574b9d"},{"name":"README.adoc","path":"modules/ssh-grunt/README.adoc","sha":"e63d38d35d3e84783818f799a158e343ac7cb97a"},{"name":"_ci","children":[{"name":"build-and-test.sh","path":"modules/ssh-grunt/_ci/build-and-test.sh","sha":"903993de2d7bcde19d472fa5e510ee862d4b10c3"},{"name":"test.sh","path":"modules/ssh-grunt/_ci/test.sh","sha":"235603944316e81f1da1cc0248b80beecf99cb27"}]},{"name":"_docs","children":[{"name":"houston-upload-ssh-key.png","path":"modules/ssh-grunt/_docs/houston-upload-ssh-key.png","sha":"e32519497262f9796a4ea46c53953923975cbd7d"},{"name":"iam-upload-ssh-key.png","path":"modules/ssh-grunt/_docs/iam-upload-ssh-key.png","sha":"8bb1e793185eb0b4822023552899874394342f21"}]},{"name":"core-concepts.md","path":"modules/ssh-grunt/core-concepts.md","sha":"8c7b359b4fbfd52aa18124efe06f1304edbf2db2","toggled":true},{"name":"docker-compose.yml","path":"modules/ssh-grunt/docker-compose.yml","sha":"74a2c67f6b9dc838ff3bd9c9c5aa68c813db1f0d"},{"name":"go.mod","path":"modules/ssh-grunt/go.mod","sha":"33e7bfc12450f68fe0fc800d06248129ed229b9f"},{"name":"go.sum","path":"modules/ssh-grunt/go.sum","sha":"9c21e75d8e59393633a732fe8b646daedf4ac139"},{"name":"scripts","children":[{"name":"build-linux-binary.sh","path":"modules/ssh-grunt/scripts/build-linux-binary.sh","sha":"2d91cbed3db40f419e6a440ce2735b9d3f2d048b"},{"name":"run.sh","path":"modules/ssh-grunt/scripts/run.sh","sha":"050027e034cd03e53625986eb0f331c043492cf6"}]},{"name":"src","children":[{"name":"cli.go","path":"modules/ssh-grunt/src/cli.go","sha":"d12bfb946f3c5268afbc9ac012134e831b2a3ec7"},{"name":"cli_test.go","path":"modules/ssh-grunt/src/cli_test.go","sha":"9bac2a34c06455e1b7fe913afe61e54b2ae754b2"},{"name":"collections.go","path":"modules/ssh-grunt/src/collections.go","sha":"aa9b67f00f57088f9bf4e129dcc53003524dd0a7"},{"name":"cron.go","path":"modules/ssh-grunt/src/cron.go","sha":"4ceb8efd0cdf51b5170bb152b6824fc54f8d429c"},{"name":"cron_test.go","path":"modules/ssh-grunt/src/cron_test.go","sha":"4b87577a1cc2b8dbff08457d60bbc96546149174"},{"name":"ec2_instance_connect.go","path":"modules/ssh-grunt/src/ec2_instance_connect.go","sha":"0334300e45fed310b176b244f2592e2675563622"},{"name":"errors.go","path":"modules/ssh-grunt/src/errors.go","sha":"03c89804638ecc45fdcd0a0aeaed9ea5f605940b"},{"name":"file.go","path":"modules/ssh-grunt/src/file.go","sha":"eb991fd15ac2c3660313e6d4c5669b36ccc9cc21"},{"name":"groups.go","path":"modules/ssh-grunt/src/groups.go","sha":"49e569a80abb6306ab0f7fd79c810d2e2ad8ab3a"},{"name":"groups_test.go","path":"modules/ssh-grunt/src/groups_test.go","sha":"7e54ba9b640b07605ae959de086fc6998861e311"},{"name":"houston.go","path":"modules/ssh-grunt/src/houston.go","sha":"e9db062f2cb815b49e4df754427ae286e4d163d4"},{"name":"houston_test.go","path":"modules/ssh-grunt/src/houston_test.go","sha":"82a9b2d2d41e09b6949897ed989a483fc7e0a650"},{"name":"iam.go","path":"modules/ssh-grunt/src/iam.go","sha":"dafbc8fbb732d2d6212cade786eb13d7215b9862"},{"name":"iam_test.go","path":"modules/ssh-grunt/src/iam_test.go","sha":"9c11adba27799e318ea9c1abb843ffbb0520c880"},{"name":"logger.go","path":"modules/ssh-grunt/src/logger.go","sha":"93095ba8216709b3178fcc44a76421a765f4e302"},{"name":"main.go","path":"modules/ssh-grunt/src/main.go","sha":"a89d9402d32d371dc9b945ab9c72996808d17b85"},{"name":"shell.go","path":"modules/ssh-grunt/src/shell.go","sha":"7f49eeee4119efde0bd58d7c78fd4ef785dc5f6c"},{"name":"ssh.go","path":"modules/ssh-grunt/src/ssh.go","sha":"8e6b62d6c33279aaf5af6cabacd0afc4d186ca97"},{"name":"ssh_test.go","path":"modules/ssh-grunt/src/ssh_test.go","sha":"7500d8fd85ef74758501f6952be45cb523e29cd1"},{"name":"string.go","path":"modules/ssh-grunt/src/string.go","sha":"fc61ca9625f9d654c2b3576ff932db1b90ae9dfe"},{"name":"string_test.go","path":"modules/ssh-grunt/src/string_test.go","sha":"78bf08d239079c9c985d40da1cc9bcdcb4c0bc5d"},{"name":"sync.go","path":"modules/ssh-grunt/src/sync.go","sha":"7c2f9ff292b484a7ca1ab14e1bbd558cd24553f2"},{"name":"sync_test.go","path":"modules/ssh-grunt/src/sync_test.go","sha":"2ddb07aedec67d1698af022e4e1391ea60636f9e"},{"name":"url.go","path":"modules/ssh-grunt/src/url.go","sha":"0af5ddc5f3e27af95d6f6ddd41acf0c229962f7f"},{"name":"url_test.go","path":"modules/ssh-grunt/src/url_test.go","sha":"606974cac1eee3f309a951c1d9e11ed389088836"},{"name":"users.go","path":"modules/ssh-grunt/src/users.go","sha":"6c3a8a22006a91656fcc5fd31d684271cdf129e3"},{"name":"users_test.go","path":"modules/ssh-grunt/src/users_test.go","sha":"fdd9f7f99466c223b9abdd4951147c8febc0b3fb"}]}],"toggled":true},{"name":"ssh-iam","children":[{"name":"README.md","path":"modules/ssh-iam/README.md","sha":"4aa06d6a729e53384b6d2a43c06ee38807092f32"}]},{"name":"ssm-healthchecks-iam-permissions","children":[{"name":"README.md","path":"modules/ssm-healthchecks-iam-permissions/README.md","sha":"e31ee0ce0688c6e888cd56a5d0dbd8dd60cd31e6"},{"name":"main.tf","path":"modules/ssm-healthchecks-iam-permissions/main.tf","sha":"0da24e8a2e1247966b08d3985ca0a8bdf84ecce9"},{"name":"variables.tf","path":"modules/ssm-healthchecks-iam-permissions/variables.tf","sha":"36778c58999e05f20468d118f22e8c9d754b1a4d"}]},{"name":"tls-cert-private","children":[{"name":"Dockerfile","path":"modules/tls-cert-private/Dockerfile","sha":"2d8683d51957cb17ffef180dd57b43651b1e9d23"},{"name":"README.md","path":"modules/tls-cert-private/README.md","sha":"c6996ec25d7d9b1ab4f79d8164a14e86e1ac844f"},{"name":"docker-compose.yml","path":"modules/tls-cert-private/docker-compose.yml","sha":"f872026e8d51ceaab2e1c11cc9cf9c35ba81f29c"},{"name":"files","children":[{"name":"openssl.cnf","path":"modules/tls-cert-private/files/openssl.cnf","sha":"2542542c80ab180c47d3e0a27dbded65bed572de"}]},{"name":"scripts","children":[{"name":"generate-ca-keypair.sh","path":"modules/tls-cert-private/scripts/generate-ca-keypair.sh","sha":"395ee97c0e499c660efac5c5cf1f79dfcdbb69f8"},{"name":"generate-tls-keypair.sh","path":"modules/tls-cert-private/scripts/generate-tls-keypair.sh","sha":"f1c3577437fd589087704a9c003de416cb87d232"},{"name":"main.sh","path":"modules/tls-cert-private/scripts/main.sh","sha":"dc7af965ffb783bbef449010818e69294fa2ef75"}]}]}],"toggled":true},{"name":"terraform-cloud-enterprise-private-module-registry-placeholder.tf","path":"terraform-cloud-enterprise-private-module-registry-placeholder.tf","sha":"ae586c0fe830819580e1009d41a9074f16e65bed"},{"name":"test","children":[{"name":"README.md","path":"test/README.md","sha":"b44e2152ea21d65a8c51bb58321e18ec7527c22e"},{"name":"common","children":[{"name":"test_helpers.go","path":"test/common/test_helpers.go","sha":"d42b5149d99dd3fce84a7cef158a8cea44be3c99"}]},{"name":"go.mod","path":"test/go.mod","sha":"b9aef1489646f481264e4d7ad05512f760e8b752"},{"name":"go.sum","path":"test/go.sum","sha":"5afc859e501c7f8053cb59c4148dbaafc570515c"},{"name":"landingzone","children":[{"name":"account_baseline_test.go","path":"test/landingzone/account_baseline_test.go","sha":"2e79014b70907d5d5e585c242b948b5457b3cb87"},{"name":"aws_config_rules_test.go","path":"test/landingzone/aws_config_rules_test.go","sha":"5ba837a0b32138242058f26e0847919d0b97402a"},{"name":"aws_config_test.go","path":"test/landingzone/aws_config_test.go","sha":"27cc3b13cc2bbe2f416dbb26a33b9f8bb1194d40"},{"name":"aws_organizations_test.go","path":"test/landingzone/aws_organizations_test.go","sha":"b8b2a9d87d27b48adf3190d9254fe565e27e2834"},{"name":"ebs_encryption_multi_region_test.go","path":"test/landingzone/ebs_encryption_multi_region_test.go","sha":"1e6fe967e38b462830a32262843a9f29bf2819c7"},{"name":"guardduty_test.go","path":"test/landingzone/guardduty_test.go","sha":"99228563507fa0f58b26bec4d1b627a268a65682"},{"name":"iam_access_analyzer_multiregion_test.go","path":"test/landingzone/iam_access_analyzer_multiregion_test.go","sha":"39a6619be16a0ccaf6040db7f01354423e205b68"},{"name":"kms_grant_multiregion_test.go","path":"test/landingzone/kms_grant_multiregion_test.go","sha":"5be13e31498eb7e93550d4306e92b773f7f43e04"},{"name":"kms_master_key_multiregion_test.go","path":"test/landingzone/kms_master_key_multiregion_test.go","sha":"4f718b41f6f1f0d4c1a0daded1a42f1bdf99993b"},{"name":"test_helpers.go","path":"test/landingzone/test_helpers.go","sha":"aae47078a9627d3a45ebddd3cf492ff4c0f0c279"}]},{"name":"security","children":[{"name":"auto_update_test.go","path":"test/security/auto_update_test.go","sha":"c55fc7bde4cdd3ff7301d6b066133a3b00393677"},{"name":"cloudtrail_test.go","path":"test/security/cloudtrail_test.go","sha":"80e8c65daaa74ed3c3dae8ea7c5b1e625c5a12a4"},{"name":"cross_account_iam_roles_test.go","path":"test/security/cross_account_iam_roles_test.go","sha":"889923cccfaf4775a15a0e500a810bc78fafd55f"},{"name":"custom_iam_entity_test.go","path":"test/security/custom_iam_entity_test.go","sha":"514a06c2e5bab3c0537b67e9c75e33629248cfcd"},{"name":"fail2ban_test.go","path":"test/security/fail2ban_test.go","sha":"41ac99ac68c6771e9e61a6716bc92c5bc226537a"},{"name":"iam_groups_test.go","path":"test/security/iam_groups_test.go","sha":"e0a7ae52a0b0edcb1aee42db4eff686c994f263b"},{"name":"iam_ssm_test.go","path":"test/security/iam_ssm_test.go","sha":"20268ac744df04c901a1cbf81d042c1f535e5371"},{"name":"iam_user_password_policy_test.go","path":"test/security/iam_user_password_policy_test.go","sha":"e6eea3e767a427352fe9f0226e7fa3c39ed338d6"},{"name":"iam_users_test.go","path":"test/security/iam_users_test.go","sha":"d71b6d7f8f215a05afbd84e5043fe5b0baf9f012"},{"name":"ip-lockdown-test-scripts","children":[{"name":"allow-several-users.sh","path":"test/security/ip-lockdown-test-scripts/allow-several-users.sh","sha":"2f75dbe0880ed0907b43db58b6ac030a0d0e9bd4"},{"name":"common.sh","path":"test/security/ip-lockdown-test-scripts/common.sh","sha":"cdfe11aca76607a4feaf254a394f32273b738c5c"},{"name":"index.html","path":"test/security/ip-lockdown-test-scripts/index.html","sha":"557db03de997c86a4a028e1ebd3a1ceb225be238"},{"name":"restrict-all-users.sh","path":"test/security/ip-lockdown-test-scripts/restrict-all-users.sh","sha":"a37c1ffc90f2532e7cc3f9f5a859b75c98661dc6"},{"name":"restrict-one-user.sh","path":"test/security/ip-lockdown-test-scripts/restrict-one-user.sh","sha":"4214e1c15102f4568d1e995aa82add46ee430237"},{"name":"sanity-check.sh","path":"test/security/ip-lockdown-test-scripts/sanity-check.sh","sha":"542ed72f4f0952ace67c9cbf2e5ac07e81e6870c"}]},{"name":"ip_lockdown_test.go","path":"test/security/ip_lockdown_test.go","sha":"14d5236b574215f568131ba7f915ba2812d92c55"},{"name":"kms_master_key_test.go","path":"test/security/kms_master_key_test.go","sha":"b9addac57172419069956f4fb2db8424d32fa2ff"},{"name":"ntp_test.go","path":"test/security/ntp_test.go","sha":"38c92a6ecc39a49629d6ff2f072e849da17ff2ec"},{"name":"os_hardening_test.go","path":"test/security/os_hardening_test.go","sha":"c50ac78e1b70a8b1cea2ac4b56de433795ef3a1e"},{"name":"private_s3_bucket_test.go","path":"test/security/private_s3_bucket_test.go","sha":"e651e78d37b1227e207a518142acb93c8c0e8486"},{"name":"saml_iam_roles_test.go","path":"test/security/saml_iam_roles_test.go","sha":"c74cf88af9132ddd9f1a587f5182594f388326d8"},{"name":"secrets_manager_resource_policies_test.go","path":"test/security/secrets_manager_resource_policies_test.go","sha":"07f69b66238517d1f8af61eb9751248372997b70"},{"name":"ssh_grunt_iam_test.go","path":"test/security/ssh_grunt_iam_test.go","sha":"c0d79bc56c1c6206f135473df19a0a50a2fb9a3c"},{"name":"test_helpers.go","path":"test/security/test_helpers.go","sha":"fcd91c0059f4ab6701db6368fc2acda8b9d1dd60"},{"name":"test_helpers_aws_auth.go","path":"test/security/test_helpers_aws_auth.go","sha":"de42c70f5e1b875f994b433cf94f1ff6bacc7de7"},{"name":"tls_cert_private_test.go","path":"test/security/tls_cert_private_test.go","sha":"455501c058664b1066381be8c1423e68ba436fdf"}]}]}]},"detailsContent":"<h2 class=\"preview__body--subtitle\" id=\"setup-instructions\">Setup instructions</h2>\n<p>To use <code>ssh-grunt</code>, you need to do the following:</p>\n<ol>\n<li><a href=\"#upload-public-ssh-keys\" class=\"preview__body--description--blue\">Upload public SSH Keys</a></li>\n<li><a href=\"#install-ssh-grunt-on-your-servers\" class=\"preview__body--description--blue\">Install ssh-grunt on your servers</a></li>\n<li><a href=\"#set-up-iam-permissions\" class=\"preview__body--description--blue\">Set up IAM permissions</a></li>\n<li><a href=\"#test-it-out\" class=\"preview__body--description--blue\">Test it out</a></li>\n</ol>\n<p>See the <a href=\"/repos/v0.53.1/module-security/examples/ssh-grunt\" class=\"preview__body--description--blue\">ssh-grunt example</a> for fully working code samples.</p>\n<h3 class=\"preview__body--subtitle\" id=\"upload-public-ssh-keys\">Upload public SSH Keys</h3>\n<p>Each developer on your team will need to <a href=\"#upload-public-ssh-keys-to-iam\" class=\"preview__body--description--blue\">upload public SSH Keys to IAM</a>.</p>\n<h4 id=\"upload-public-ssh-keys-to-iam\">Upload public SSH Keys to IAM</h4>\n<p>Login to the <a href=\"https://console.aws.amazon.com/iam/home\" class=\"preview__body--description--blue\" target=\"_blank\">IAM console</a> and click on your User Name in the Users section.\nAt the bottom of the Security Credentials tab, click the "Upload SSH public key" button, and enter the contents of\nyour public SSH key (which is typically stored in <code>~/.ssh/id_rsa.pub</code>):</p>\n<p><img src=\"/repos/images/v0.53.1/module-security/modules/ssh-grunt/_docs/iam-upload-ssh-key.png\" alt=\"Upload public SSH Key to IAM\" class=\"preview__body--diagram\"></p>\n<h3 class=\"preview__body--subtitle\" id=\"install-ssh-grunt-on-your-servers\">Install ssh-grunt on your servers</h3>\n<p><code>ssh-grunt</code> consists of a single binary. The easiest way to get it onto your servers is to use the <a href=\"/repos/gruntwork-installer\" class=\"preview__body--description--blue\">Gruntwork\nInstaller</a> (make sure to replace <code><VERSION></code> below with the latest\nversion from the <a href=\"#open_modal\" class=\"preview__body--description--blue\">releases page</a>):</p>\n<pre>gruntwork-install --binary-name ssh-grunt --repo https://github.com/gruntwork-io/<span class=\"hljs-keyword\">terraform</span>-aws-security --tag <VERSION>\n</pre>\n<p>Alternatively, you can download the binary from the <a href=\"#open_modal\" class=\"preview__body--description--blue\">Releases\nPage</a>. On systems with SELinux, such as CentOS, you'll also\nneed to install the <a href=\"/repos/v0.53.1/module-security/modules/ssh-grunt-selinux-policy\" class=\"preview__body--description--blue\">ssh-grunt-selinux-policy module</a>.</p>\n<p><strong>Important note</strong>: We recommend installing <code>ssh-grunt</code> as part of a <a href=\"https://www.packer.io/\" class=\"preview__body--description--blue\" target=\"_blank\">Packer template</a> and\nbuilding an AMI with it. If you are installing <code>ssh-grunt</code> interactively (e.g., for learning / experimentation) or\nas part of a User Data script, then you must restart <code>sshd</code> in order for the changes above to take effect! E.g.,\ndepending on your OS, you'd have to run something like:</p>\n<pre>sudo<span class=\"hljs-built_in\"> service </span>sshd reload\n</pre>\n<p>Once the binary is on the server, use <code>ssh-grunt</code> to complete the configuration:</p>\n<pre>ssh-grunt iam install \\\n --iam-<span class=\"hljs-keyword\">group</span> <span class=\"hljs-title\">ssh-group</span> \\\n --iam-group-sudo ssh-sudo-<span class=\"hljs-keyword\">group</span>\n<span class=\"hljs-title\"></span></pre>\n<p>The <code>install</code> command does two things:</p>\n<ol>\n<li>Create a cron job to run <code>ssh-grunt iam sync-users</code> to periodically (by default, every 30 minutes) sync user accounts\nfrom the IAM Groups specified via the <code>--iam-group</code> and <code>--iam-group-sudo</code> option.</li>\n<li>Configure SSH to use <code>ssh-grunt iam print-keys</code> to authenticate login attempts using public keys in IAM.</li>\n</ol>\n<p><strong>Important note</strong>: If <code>ec2-instance-connect</code> is installed, it will conflict with the operability of <code>ssh-grunt</code>.\nWhen you run the <code>install</code> command, it will detect the existence of <code>ec2-instance-connect</code> and warn you. The easiest\nsolution is to remove the <code>ec2-instance-connect</code> package via <code>apt-get remove</code> or <code>yum remove</code>.</p>\n<p>You can pass in multiple <code>--iam-group</code> and <code>--iam-group-sudo</code> to sync users associated with different IAM groups. For\nexample, if you ran:</p>\n<pre>ssh-grunt iam install \\\n --iam-<span class=\"hljs-keyword\">group</span> <span class=\"hljs-title\">ssh-group-dev</span> \\\n --iam-<span class=\"hljs-keyword\">group</span> <span class=\"hljs-title\">ssh-group-stage</span>\n</pre>\n<p><code>ssh-grunt</code> will sync users associated with EITHER the <code>ssh-group-dev</code> IAM group or <code>ssh-group-stage</code> IAM group.</p>\n<p>See the <a href=\"#cli-docs\" class=\"preview__body--description--blue\">CLI docs</a> for the full list of available options.</p>\n<h3 class=\"preview__body--subtitle\" id=\"set-up-iam-permissions\">Set up IAM permissions</h3>\n<p>You need to configure IAM permissions on each server where <code>ssh-grunt</code> is running so that it can access your IdP:</p>\n<ol>\n<li><a href=\"#iam-permissions-for-ssh-grunt-with-iam\" class=\"preview__body--description--blue\">IAM permissions for ssh-grunt with IAM</a></li>\n</ol>\n<h4 id=\"iam-permissions-for-ssh-grunt-with-iam\">IAM permissions for ssh-grunt with IAM</h4>\n<p>The IAM permissions you need to configure for <code>ssh-grunt</code> depend on whether your infrastructure is deployed in a\nsingle AWS account or multiple AWS accounts:</p>\n<ol>\n<li><a href=\"#single-aws-account-with-iam\" class=\"preview__body--description--blue\">Single AWS account with IAM</a></li>\n<li><a href=\"#multiple-aws-accounts-with-iam\" class=\"preview__body--description--blue\">Multiple AWS accounts with IAM</a></li>\n</ol>\n<h5 id=\"single-aws-account-with-iam\">Single AWS account with IAM</h5>\n<p><code>ssh-grunt</code> retrieves info from IAM using the AWS API. To use the API, <code>ssh-grunt</code> needs:</p>\n<ol>\n<li>AWS credentials: the best way to provide credentials is to attach an <a href=\"http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html\" class=\"preview__body--description--blue\" target=\"_blank\">IAM\nRole</a> to the EC2 Instance.</li>\n<li>IAM permissions: <code>ssh-grunt</code> needs an <a href=\"http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html\" class=\"preview__body--description--blue\" target=\"_blank\">IAM\nPolicy</a> that allows the <code>iam:GetGroup</code>,\n<code>iam:ListSSHPublicKeys</code>, and <code>iam:GetSSHPublicKey</code> actions. The <a href=\"/repos/v0.53.1/module-security/modules/iam-policies\" class=\"preview__body--description--blue\">iam-policies module</a> can\nprovide the IAM policy with these permissions for you in the output variable <code>ssh_grunt_permissions</code>.</li>\n</ol>\n<p>Check out the <a href=\"/repos/v0.53.1/module-security/examples/ssh-grunt\" class=\"preview__body--description--blue\">ssh-grunt example</a> for sample code.</p>\n<h5 id=\"multiple-aws-accounts-with-iam\">Multiple AWS accounts with IAM</h5>\n<p>If you have multiple AWS accounts, with all IAM users defined in one account (e.g., the "security" account), and EC2\nInstances running in various other AWS accounts (e.g., the "dev" and "prod" accounts), then you need to give\n<code>ssh-grunt</code> running on those EC2 Instances permissions to access the account where users and groups are defined:</p>\n<ol>\n<li>\n<p>In the AWS account where the IAM users are defined, use the <a href=\"/repos/v0.53.1/module-security/modules/cross-account-iam-roles\" class=\"preview__body--description--blue\">cross-account-iam-roles\nmodule</a> to create an IAM role that allows your other AWS account(s) to access IAM\nGroup and public SSH key info by specifying the ARNs of those other accounts in the\n<code>allow_ssh_grunt_access_from_other_account_arns</code> input variable. Rough example:</p>\n<pre><span class=\"hljs-keyword\">module</span> <span class=\"hljs-string\">\"cross_account_iam_roles\"</span> {\n source = <span class=\"hljs-string\">\"git::git@github.com:gruntwork-io/terraform-aws-security.git//modules/cross-account-iam-roles?ref=v1.0.8\"</span>\n\n allow_ssh_grunt_access_from_other_account_arns = [<span class=\"hljs-string\">\"arn:aws:iam::123445678910:root\"</span>]\n\n <span class=\"hljs-comment\"># ... (other params ommitted) ...</span>\n}\n</pre>\n</li>\n<li>\n<p>In the AWS accounts where <code>ssh-grunt</code> is running, give the EC2 Instances that run <code>ssh-grunt</code> an IAM role that has\npermissions to assume an IAM role in the users account. You can create the IAM policy with this permission using\nthe <a href=\"/repos/v0.53.1/module-security/modules/iam-policies\" class=\"preview__body--description--blue\">iam-policies module</a> by specifying the ARN of the IAM role you created in the users\naccount in the previous step in the <code>allow_access_to_other_account_arns</code> input variable and adding the policy in\nthe <code>allow_access_to_other_accounts</code> output variable to the EC2 Instance's IAM role.</p>\n<pre><span class=\"hljs-keyword\">module</span> <span class=\"hljs-string\">\"iam_policies\"</span> {\n source = <span class=\"hljs-string\">\"git::git@github.com:gruntwork-io/terraform-aws-security.git//modules/iam-policies?ref=v1.0.8\"</span>\n\n <span class=\"hljs-comment\"># ssh-grunt is an automated app, so we can't use MFA with it</span>\n trust_policy_should_require_mfa = false\n iam_policy_should_require_mfa = false\n allow_access_to_other_account_arns = [[<span class=\"hljs-string\">\"arn:aws:iam::111111111111:role/allow-ssh-grunt-access-from-other-accounts\"</span>]]\n <span class=\"hljs-comment\"># ... (other params ommitted) ...</span>\n}\n\n<span class=\"hljs-keyword\">resource</span> <span class=\"hljs-string\">\"aws_iam_role_policy\"</span> <span class=\"hljs-string\">\"ssh_grunt_external_account_permissions\"</span> {\n name = <span class=\"hljs-string\">\"ssh-grunt-external-account-permissions\"</span>\n role = <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${module.example_instance.iam_role_id}</span>\"</span>\n policy = <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${<span class=\"hljs-meta\">element(module.iam_policies.allow_access_to_other_accounts, <span class=\"hljs-number\">0</span>)</span>}</span>\"</span>\n}\n</pre>\n</li>\n<li>\n<p>When you're calling <code>ssh-grunt iam install</code>, pass the ARN of the IAM role from the other account using <code>--role-arn</code>\nargument.</p>\n<pre>ssh-grunt iam install \\\n -<span class=\"ruby\">-iam-group ssh-users \\\n</span> -<span class=\"ruby\">-role-arn <span class=\"hljs-symbol\">arn:</span><span class=\"hljs-symbol\">aws:</span>iam::<span class=\"hljs-number\">111111111111</span><span class=\"hljs-symbol\">:role/allow-ssh-grunt-access-from-other-accounts</span>\n</span></pre>\n</li>\n</ol>\n<p>Check out the <a href=\"/repos/v0.53.1/module-security/examples/ssh-grunt\" class=\"preview__body--description--blue\">ssh-grunt example</a> for sample code and pay attention to the <code>external_account_arn</code>\ninput variable.</p>\n<h3 class=\"preview__body--subtitle\" id=\"test-it-out\">Test it out</h3>\n<p>You should now be able to SSH to your servers using your IdP user name and public key (note, if a server has just\nbooted, it will only sync users from your IdP after ~90 seconds, so be patient!). For example, if you installed\n<code>ssh-grunt</code> on an EC2 Instance with IP address <code>11.22.33.44</code> and your IdP user name is <code>grunt</code>, you can now connect to\nthe server as follows:</p>\n<pre>ssh <span class=\"hljs-symbol\">grunt@</span><span class=\"hljs-number\">11.22</span><span class=\"hljs-number\">.33</span><span class=\"hljs-number\">.44</span>\n</pre>\n<p>That's all there is to it! No Key Pair files or passwords to worry about and as you update users in IAM, your servers\nwill sync up automatically!</p>\n<p>To learn more, check out the <a href=\"#how-it-works\" class=\"preview__body--description--blue\">How it works</a> docs to see what's happening under the hood, and the\n<a href=\"#cli-docs\" class=\"preview__body--description--blue\">CLI docs</a> to learn all the parameters and options you can tweak.</p>\n<h2 class=\"preview__body--subtitle\" id=\"how-it-works\">How it works</h2>\n<p><code>ssh-grunt</code> consts of two main pieces:</p>\n<ol>\n<li><a href=\"#syncing-users\" class=\"preview__body--description--blue\">Syncing users</a></li>\n<li><a href=\"#authenticating-requests-with-public-keys\" class=\"preview__body--description--blue\">Authenticating requests with public keys</a></li>\n</ol>\n<h3 class=\"preview__body--subtitle\" id=\"syncing-users\">Syncing users</h3>\n<p><code>ssh-grunt</code> can automatically sync users from:</p>\n<ol>\n<li><a href=\"#syncing-users-from-iam\" class=\"preview__body--description--blue\">Syncing users from IAM</a></li>\n</ol>\n<h4 id=\"syncing-users-from-iam\">Syncing users from IAM</h4>\n<p>When you run <code>ssh-grunt iam install</code>, it adds a cron job that periodically runs the <code>ssh-grunt iam sync-users</code> command.\nThe <code>sync-users</code> command does the following:</p>\n<ol>\n<li>Fetch the users from the IAM Group specified via the <code>--iam-group</code> option and for each one, create an OS user on\nthe EC2 Instance. All of these OS users get added to the OS group <code>ssh-grunt-non-sudo-group</code>.</li>\n<li>Fetch the users from the IAM Group specified via the <code>--iam-group-sudo</code> option and for each one, create an OS user\nthat has sudo privileges on the EC2 Instance. All of these OS users get added to the OS group <code>ssh-grunt-sudo-group</code>.</li>\n<li>Remove any users in the <code>ssh-grunt-non-sudo-group</code> and <code>ssh-grunt-sudo-group</code> groups that are not in the corresponding\nIAM group.</li>\n</ol>\n<h4 id=\"a-note-on-user-names\">A note on user names</h4>\n<p>Note that the requirements for OS user names are stricter than those of other IdPs, such as IAM. Therefore, the OS user\nname created by the <code>sync-users</code> command may not exactly match your IdP user name. In particular, OS user names must\nstart with a letter, followed by letters, numbers, underscores, and dashes, and be no more than 32 characters long.\nTherefore, <code>ssh-grunt</code> does the following:</p>\n<ol>\n<li>Drop anything after the @ symbol in email addresses (e.g. "foo@bar.com" --> "foo").</li>\n<li>Replace whitespace and periods with underscores (e.g. "foo.bar baz" --> "foo_bar_baz").</li>\n<li>Drop all other illegal characters (e.g. "foo$@%,!bar" --> "foobar").</li>\n<li>Drop any leading punctuation or numbers (e.g. ".,123foo" --> "foo").</li>\n<li>Truncate all strings over 32 characters long.</li>\n</ol>\n<p>We store the original user name in the comment field of the OS user so we can retrieve it when the user tries to\nauthenticate with their public key.</p>\n<h3 class=\"preview__body--subtitle\" id=\"authenticating-requests-with-public-keys\">Authenticating requests with public keys</h3>\n<p>When you run <code>install</code> command of <code>ssh-grunt</code>, it modifies the <code>AuthorizedKeysCommand</code> in <code>/etc/ssh/sshd_config</code>. When\na user tries to connect via SSH, SSH will execute the <code>AuthorizedKeysCommand</code> (passing it the username as the first\nargument) and whatever text that command writes to stdout will be used as the <code>authorized_keys</code>—that is, the list of\npublic keys that are allowed to connect to the server.</p>\n<p>We take advantage of this <code>AuthorizedKeysCommand</code> by configuring it to run <code>ssh-grunt iam print-keys</code>,\nwhich looks up the user's public keys in IAM and prints all the\nactive keys to stdout. That way, all a user has to do is upload their public keys to IAM and they will be\nable to authenticate to any server with <code>ssh-grunt</code>.</p>\n<p>Note that SSH is very picky about the program it executes for the <code>AuthorizedKeysCommand</code> (See the <a href=\"http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/sshd_config.5\" class=\"preview__body--description--blue\" target=\"_blank\">sshd_config\ndocs</a> for details):</p>\n<ul>\n<li>The program must not use any custom arguments, must be owned by root, must not be writable by group or others, and\nmust be specified by an absolute path. To meet these requirements, we create a script under <code>/opt/ssh-grunt</code> that runs\nthe <code>print-keys</code> command of <code>ssh-grunt</code>.</li>\n<li>The program must be executed under a user specified via the <code>AuthorizedKeysCommandUser</code> configuration. By default,\nwe set this configuration to the user that runs the <code>install</code> command of <code>ssh-grunt</code>.</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"cli-docs\">CLI docs</h2>\n<p><code>ssh-grunt</code> supports the following commands:</p>\n<ol>\n<li><a href=\"#iam-print-keys-command\" class=\"preview__body--description--blue\">iam print-keys</a></li>\n<li><a href=\"#iam-sync-users-command\" class=\"preview__body--description--blue\">iam sync-users</a></li>\n<li><a href=\"#iam-install-command\" class=\"preview__body--description--blue\">iam install</a></li>\n</ol>\n<p>You can run <code>ssh-grunt --help</code> at any time to see the CLI docs.</p>\n<h3 class=\"preview__body--subtitle\" id=\"iam-print-keys-command\">iam print-keys command</h3>\n<p>Usage: <code>ssh-grunt iam print-keys [OPTIONS] USERNAME</code></p>\n<p>Description: Find the public keys stored for the specified IAM user and print them to stdout.</p>\n<p>Arguments:</p>\n<ul>\n<li><code>USERNAME</code> (required): Look up the public keys for this IAM user name.</li>\n</ul>\n<p>Options:</p>\n<ul>\n<li><code>--role-arn</code> (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and\ngroups are defined in another AWS account.</li>\n</ul>\n<p>Examples:</p>\n<pre>ssh-grunt iam <span class=\"hljs-keyword\">print</span>-<span class=\"hljs-keyword\">keys</span> grunt\n</pre>\n<h3 class=\"preview__body--subtitle\" id=\"iam-sync-users-command\">iam sync-users command</h3>\n<p>Usage: <code>ssh-grunt iam sync-users [OPTIONS]</code></p>\n<p>Description: Sync the user accounts on this system with the user accounts in the specified IAM groups.</p>\n<p>Options:</p>\n<ul>\n<li><code>--iam-group</code> (optional): Sync the user accounts on this system with the user accounts in this IAM group. At least\none of <code>--iam-group</code> or <code>--iam-group-sudo</code> is required.</li>\n<li><code>--iam-group-sudo</code> (optional): Sync the user accounts on this system with the user accounts in this IAM group and\ngive these user accounts sudo privileges. At least one of <code>--iam-group</code> or <code>--iam-group-sudo</code> is required.</li>\n<li><code>--role-arn</code> (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and\ngroups are defined in another AWS account.</li>\n<li><code>--force-user-deletion</code> (optional): If this flag is set, delete not only the OS user, but also their home directory\nwhen that user is removed from an ssh-grunt managed group.</li>\n<li><code>--dry-run</code> (optional): Print out what this command would do, but don't actually make any changes on this system.</li>\n</ul>\n<p>Examples:</p>\n<pre>ssh-grunt iam sync-users \\\n --iam-<span class=\"hljs-keyword\">group</span> <span class=\"hljs-title\">ssh-group</span> \\\n --iam-group-sudo ssh-sudo-<span class=\"hljs-keyword\">group</span>\n<span class=\"hljs-title\"></span></pre>\n<h3 class=\"preview__body--subtitle\" id=\"iam-install-command\">iam install command</h3>\n<p>Usage: <code>ssh-grunt iam install [OPTIONS]</code></p>\n<p>Description: Configure this server to a) periodically sync user accounts from IAM and b) use ssh-grunt to authenticate\nSSH connections.</p>\n<p>Options:</p>\n<ul>\n<li><code>--iam-group</code> (optional): Sync the user accounts on this system with the user accounts in this IAM group. At least\none of <code>--iam-group</code> or <code>--iam-group-sudo</code> is required.</li>\n<li><code>--iam-group-sudo</code> (optional): Sync the user accounts on this system with the user accounts in this IAM group and\ngive these user accounts sudo privileges. At least one of <code>--iam-group</code> or <code>--iam-group-sudo</code> is required.</li>\n<li><code>--cron-schedule</code> (optional): A cron expression that controls how often <code>ssh-grunt</code> syncs IAM users to this system.\nDefault: <code>*/30 * * * *</code> (every 30 minutes).</li>\n<li><code>--authorized-keys-command-user</code> (optional): The user that should execute the SSH AuthorizedKeysCommand. Default:\ncurrent user.</li>\n<li><code>--role-arn</code> (optional): Assume this IAM role for all API calls to AWS. This is used primarily when the IAM users and\ngroups are defined in another AWS account.</li>\n<li><code>--force-user-deletion</code> (optional): If this flag is set, delete not only the OS user, but also their home directory\nwhen that user is removed from an ssh-grunt managed group.</li>\n<li><code>--dry-run</code> (optional): Print out what this command would do, but don't actually make any changes on this system.</li>\n</ul>\n<p>Examples:</p>\n<pre>ssh-grunt iam install \\\n --iam-<span class=\"hljs-keyword\">group</span> <span class=\"hljs-title\">ssh-users</span> \\\n --iam-group-sudo ssh-sudo-users\n</pre>\n<h2 class=\"preview__body--subtitle\" id=\"threat-model\">Threat model</h2>\n<p>The threat model is defined in terms of what each possible attacker can achieve.</p>\n<p>At a high level, the security of <code>ssh-grunt</code> is predicated on the security of SSH, your IdP, and Gruntwork.</p>\n<h3 class=\"preview__body--subtitle\" id=\"assumptions\">Assumptions</h3>\n<ul>\n<li>Your users act reasonably and do not reveal their secrets, such as their private SSH keys or IdP credentials.</li>\n<li>SSH is a secure protocol and public/private key encryption guarantees are valid.</li>\n<li>The AWS APIs are properly secured by TLS and IAM Roles.</li>\n<li>The user's computer and your servers are not compromised by malware.</li>\n<li>The copy of <code>ssh-grunt</code> running on your servers has not been compromised by malware.</li>\n</ul>\n<h3 class=\"preview__body--subtitle\" id=\"threats-from-an-ssh-compromise\">Threats from an SSH compromise</h3>\n<p>If an attacker gets access to one of your developer's private keys, they will be able to:</p>\n<ul>\n<li>Make arbitrary changes on the server, especially if your developer had sudo access.</li>\n<li>Use any IAM Roles attached to that server to authenticate to the AWS APIs. In particular, the IAM Roles you need to\nuse <code>ssh-grunt</code> will allow the attacker to list the user names and public keys of other SSH users.</li>\n</ul>\n<p>Possible remediation: Delete the compromised key from IAM as soon as possible, and the attacker will no\nlonger be able to connect to your servers.</p>\n<h3 class=\"preview__body--subtitle\" id=\"threats-from-an-iam-compromise\">Threats from an IAM compromise</h3>\n<p>If you are using <code>gruntssh</code> with IAM, and your server cannot communicate with IAM, either due to an outage in AWS or a\nmisconfiguration on your servers:</p>\n<ul>\n<li>Your developers will not be able to authenticate to your servers using their public keys.</li>\n<li>User accounts will no longer automatically sync to the servers, so changes in IAM groups will not be reflected on\nyour servers.</li>\n</ul>\n<p>Possible remediation: Always launch servers with an <a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html\" class=\"preview__body--description--blue\" target=\"_blank\">EC2 Key\nPair</a> as backup. This Key Pair should kept on\na trusted admin's computer, not shared with anyone else (if you must share it, make sure to encrypt it thoroughly using\nsomething like <a href=\"https://aws.amazon.com/kms/\" class=\"preview__body--description--blue\" target=\"_blank\">KMS</a> or <a href=\"http://keybase.io/\" class=\"preview__body--description--blue\" target=\"_blank\">Keybase</a>), and only used in case of\nemergencies.</p>\n<p>If an attacker gets access to an IAM user account, they will be able to:</p>\n<ul>\n<li>Make arbitrary changes to your AWS account, depending on the permissions attached to that IAM account.</li>\n<li>Add their own public key to their IAM account and add that account to an IAM group that has SSH access. This will\nallow them to SSH to your servers using their public key and make arbitrary changes.</li>\n</ul>\n<p>Possible remediation: Require all IAM users to use <a href=\"https://aws.amazon.com/iam/details/mfa/\" class=\"preview__body--description--blue\" target=\"_blank\">Multi-Factor\nAuthentication</a> and secure passwords to reduces the chances of an account\nbeing compromised. You can even require <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html\" class=\"preview__body--description--blue\" target=\"_blank\">Multi-Factor Authentication for particularly sensitive API\ncalls</a>, such as any\nchanges in IAM or KMS. Follow the <a href=\"https://en.wikipedia.org/wiki/Principle_of_least_privilege\" class=\"preview__body--description--blue\" target=\"_blank\">principle of least\nprivilege</a> and grant IAM users the bare-minimum permissions\nthey need, so if an IAM account is compromised, the attacker's abilities are limited.</p>\n<h3 class=\"preview__body--subtitle\" id=\"threats-from-an-id-p-compromise\">Threats from an IdP compromise</h3>\n<p>If an attacker gets access to a user account in the IdP (e.g., ADFS or Google), they\nwill be able to:</p>\n<ul>\n<li>Make arbitrary changes to in the IdP itself, depending on the permissions attached to that IdP user.</li>\n<li>Make arbitrary changes to your AWS account, depending on the permissions attached to that IdP user.</li>\n</ul>\n<p>Possible remediation: ensure you require multi-factor authentication for your IdP and require all users to use secure\npasswords to reduce the chances of a compromised account.</p>\n<h3 class=\"preview__body--subtitle\" id=\"threats-from-a-gruntwork-compromise\">Threats from a Gruntwork compromise</h3>\n<p>If an attacker gets access to Gruntwork's repos, they will be able to:</p>\n<ul>\n<li>Replace the <code>ssh-grunt</code> binary in the <a href=\"/repos/terraform-aws-security\" class=\"preview__body--description--blue\">terraform-aws-security repo</a> with one\nthat contains malware. This will allow the attacker to make arbitrary changes on any server where <code>ssh-grunt</code> is\ninstalled.</li>\n</ul>\n<p>Possible remediation: Gruntwork only grants write access to its repos to employees, all of whom are required to use\nMulti-Factor Authentication and strong passwords. In the future, we will publish checksums of our binaries in separate\nlocations so you can use those to confirm that the binary you are installing is an authentic one.</p>\n<h2 class=\"preview__body--subtitle\" id=\"developing-ssh-grunt\">Developing ssh-grunt</h2>\n<p>Since ssh-grunt makes lots of changes to the OS (creating users, modifying SSH settings, etc), we recommend running it\nin a Docker container.</p>\n<h3 class=\"preview__body--subtitle\" id=\"building-the-docker-image\">Building the Docker image</h3>\n<p>The Docker image is defined in the <code>Dockerfile</code>. To build it, run:</p>\n<pre><span class=\"hljs-symbol\">docker</span> <span class=\"hljs-keyword\">build </span>-t gruntwork/ssh-grunt .\n</pre>\n<h3 class=\"preview__body--subtitle\" id=\"running-locally\">Running locally</h3>\n<p>To run the app locally, we've defined a <code>docker-compose.yml</code> file that mounts source code into the Docker container\n(so you don't have to keep rebuilding the container when you make source changes) and forwards our AWS environment\nvariables. To run the app with Docker Compose:</p>\n<pre>docker-compose <span class=\"hljs-builtin-name\">run</span> ssh-grunt [ARGS<span class=\"hljs-built_in\">..</span>.]\n</pre>\n<p>For example:</p>\n<pre>docker-compose <span class=\"hljs-keyword\">run</span><span class=\"bash\"> ssh-grunt iam <span class=\"hljs-built_in\">print</span>-keys myuser</span>\n</pre>\n<h3 class=\"preview__body--subtitle\" id=\"stacktraces\">Stacktraces</h3>\n<p>If you run the app and it crashes on you, set the <code>SSH_GRUNT_DEBUG</code> environment variable to any value to see the\nstacktrace:</p>\n<pre>docker-compose <span class=\"hljs-keyword\">run</span><span class=\"bash\"> -e SSH_GRUNT_DEBUG=<span class=\"hljs-literal\">true</span> ssh-grunt iam <span class=\"hljs-built_in\">print</span>-keys myuser</span>\n</pre>\n<h3 class=\"preview__body--subtitle\" id=\"running-tests\">Running tests</h3>\n<p><strong>Note</strong>: the automated tests for this repo (a) make many changes in the OS, include creating lots of OS users, so\nwe only recommend running them within a Docker container and (b) create and delete real IAM users and groups in your\nAWS account, so always let them run to completion so they can do proper cleanup.</p>\n<p>To run all the tests, use the <code>test.sh</code> script, which uses Docker Compose under the hood:</p>\n<pre>./_ci/<span class=\"hljs-keyword\">test</span>.<span class=\"hljs-keyword\">sh</span>\n</pre>\n<p>To run a specific test, use the <code>-run</code> argument:</p>\n<pre>./_ci/<span class=\"hljs-keyword\">test</span>.<span class=\"hljs-keyword\">sh</span> -<span class=\"hljs-keyword\">run</span> TestFoo\n</pre>\n<h2 class=\"preview__body--subtitle\" id=\"possible-future-additions\">Possible future additions</h2>\n<p>Some items we are considering for the future:</p>\n<ol>\n<li>Set up two-factor auth (2FA) using <code>libpam-google-authenticator</code>.</li>\n<li>Lock down SSH settings by disabling password authentication and the root user.</li>\n<li>Lock down SSH even more: https://stribika.github.io/2015/01/04/secure-secure-shell.html</li>\n<li>Send notifications for all server access: https://www.inversoft.com/guides/2016-guide-to-user-data-security#intrusion-detection</li>\n</ol>\n<p>If you're interested in these features, <a href=\"mailto:support@gruntwork.io\" class=\"preview__body--description--blue\" target=\"_blank\">let us know</a>!</p>\n","repoName":"module-security","repoRef":"v0.44.10","serviceDescriptor":{"serviceName":"ssh-grunt","serviceRepoName":"module-security","serviceRepoOrg":"gruntwork-io","serviceMainReadmePath":"/modules/ssh-grunt","cloudProviders":["aws"],"description":"Manage SSH access to EC2 Instances using groups in AWS IAM or your Identity Provider (e.g., ADFS, Google, Okta, etc).","imageUrl":"grunt.png","licenseType":"subscriber","technologies":["Terraform","Go"],"compliance":[],"tags":[""]},"serviceCategoryName":"SSH access","fileName":"core-concepts.md","filePath":"/modules/ssh-grunt/core-concepts.md","title":"Repo Browser: ssh-grunt","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}