From 33be3da1e030239d6a63b3d14f5094b99badf5a8 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 10:00:00 -0400 Subject: [PATCH 01/26] Remove unused files inherited from skeleton --- examples/basic_usage/.terraform-docs.yml | 1 - examples/basic_usage/README.md | 57 ---------------------- examples/basic_usage/main.tf | 26 ---------- examples/basic_usage/outputs.tf | 24 ---------- examples/basic_usage/variables.tf | 42 ---------------- examples/basic_usage/versions.tf | 23 --------- examples/basic_usage/vpc.tf | 20 -------- main.tf | 61 ------------------------ 8 files changed, 254 deletions(-) delete mode 120000 examples/basic_usage/.terraform-docs.yml delete mode 100644 examples/basic_usage/README.md delete mode 100644 examples/basic_usage/main.tf delete mode 100644 examples/basic_usage/outputs.tf delete mode 100644 examples/basic_usage/variables.tf delete mode 100644 examples/basic_usage/versions.tf delete mode 100644 examples/basic_usage/vpc.tf delete mode 100644 main.tf diff --git a/examples/basic_usage/.terraform-docs.yml b/examples/basic_usage/.terraform-docs.yml deleted file mode 120000 index 2afdcf8..0000000 --- a/examples/basic_usage/.terraform-docs.yml +++ /dev/null @@ -1 +0,0 @@ -../../.terraform-docs.yml \ No newline at end of file diff --git a/examples/basic_usage/README.md b/examples/basic_usage/README.md deleted file mode 100644 index d120104..0000000 --- a/examples/basic_usage/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Launch an example EC2 instance in a new VPC # - -## Usage ## - -To run this example you need to execute the `terraform init` command -followed by the `terraform apply` command. - -Note that this example may create resources which cost money. Run -`terraform destroy` when you no longer need these resources. - - -## Requirements ## - -| Name | Version | -|------|---------| -| terraform | ~> 1.0 | -| aws | ~> 4.9 | - -## Providers ## - -| Name | Version | -|------|---------| -| aws | ~> 4.9 | - -## Modules ## - -| Name | Source | Version | -|------|--------|---------| -| example | ../../ | n/a | - -## Resources ## - -| Name | Type | -|------|------| -| [aws_subnet.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | -| [aws_vpc.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | - -## Inputs ## - -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| ami\_owner\_account\_id | The ID of the AWS account that owns the AMI, or "self" if the AMI is owned by the same account as the provisioner. | `string` | `"self"` | no | -| aws\_availability\_zone | The AWS availability zone to deploy into (e.g. a, b, c, etc.). | `string` | `"a"` | no | -| aws\_region | The AWS region to deploy into (e.g. us-east-1). | `string` | `"us-east-1"` | no | -| tags | Tags to apply to all AWS resources created. | `map(string)` | ```{ "Testing": true }``` | no | -| tf\_role\_arn | The ARN of the role that can terraform non-specialized resources. | `string` | n/a | yes | - -## Outputs ## - -| Name | Description | -|------|-------------| -| arn | The EC2 instance ARN. | -| availability\_zone | The AZ where the EC2 instance is deployed. | -| id | The EC2 instance ID. | -| private\_ip | The private IP of the EC2 instance. | -| subnet\_id | The ID of the subnet where the EC2 instance is deployed. | - diff --git a/examples/basic_usage/main.tf b/examples/basic_usage/main.tf deleted file mode 100644 index efdc5bc..0000000 --- a/examples/basic_usage/main.tf +++ /dev/null @@ -1,26 +0,0 @@ -provider "aws" { - # Our primary provider uses our terraform role - assume_role { - role_arn = var.tf_role_arn - session_name = "terraform-example" - } - default_tags { - tags = var.tags - } - region = var.aws_region -} - -#------------------------------------------------------------------------------- -# Configure the example module. -#------------------------------------------------------------------------------- -module "example" { - source = "../../" - providers = { - aws = aws - } - - ami_owner_account_id = var.ami_owner_account_id - aws_availability_zone = var.aws_availability_zone - aws_region = var.aws_region - subnet_id = aws_subnet.example.id -} diff --git a/examples/basic_usage/outputs.tf b/examples/basic_usage/outputs.tf deleted file mode 100644 index 542df31..0000000 --- a/examples/basic_usage/outputs.tf +++ /dev/null @@ -1,24 +0,0 @@ -output "arn" { - description = "The EC2 instance ARN." - value = module.example.arn -} - -output "availability_zone" { - description = "The AZ where the EC2 instance is deployed." - value = module.example.availability_zone -} - -output "id" { - description = "The EC2 instance ID." - value = module.example.id -} - -output "private_ip" { - description = "The private IP of the EC2 instance." - value = module.example.private_ip -} - -output "subnet_id" { - description = "The ID of the subnet where the EC2 instance is deployed." - value = module.example.subnet_id -} diff --git a/examples/basic_usage/variables.tf b/examples/basic_usage/variables.tf deleted file mode 100644 index 70b275a..0000000 --- a/examples/basic_usage/variables.tf +++ /dev/null @@ -1,42 +0,0 @@ -# ------------------------------------------------------------------------------ -# Required parameters -# -# You must provide a value for each of these parameters. -# ------------------------------------------------------------------------------ - -variable "tf_role_arn" { - description = "The ARN of the role that can terraform non-specialized resources." - type = string -} - -# ------------------------------------------------------------------------------ -# Optional parameters -# -# These parameters have reasonable defaults. -# ------------------------------------------------------------------------------ - -variable "ami_owner_account_id" { - default = "self" - description = "The ID of the AWS account that owns the AMI, or \"self\" if the AMI is owned by the same account as the provisioner." - type = string -} - -variable "aws_availability_zone" { - default = "a" - description = "The AWS availability zone to deploy into (e.g. a, b, c, etc.)." - type = string -} - -variable "aws_region" { - default = "us-east-1" - description = "The AWS region to deploy into (e.g. us-east-1)." - type = string -} - -variable "tags" { - default = { - Testing = true - } - description = "Tags to apply to all AWS resources created." - type = map(string) -} diff --git a/examples/basic_usage/versions.tf b/examples/basic_usage/versions.tf deleted file mode 100644 index 9db27b0..0000000 --- a/examples/basic_usage/versions.tf +++ /dev/null @@ -1,23 +0,0 @@ -terraform { - # If you use any other providers you should also pin them to the - # major version currently being used. This practice will help us - # avoid unwelcome surprises. - required_providers { - # Version 4.9 of the Terraform AWS provider made changes to the S3 bucket - # refactor that is in place for versions 4.0-4.8 of the provider. With v4.9 - # only non-breaking changes and deprecation notices are introduced. Using - # this version will simplify migration to the new, broken out AWS S3 bucket - # configuration resources. Please see - # https://github.com/hashicorp/terraform-provider-aws/pull/23985 - # for more information about the changes in v4.9 and - # https://www.hashicorp.com/blog/terraform-aws-provider-4-0-refactors-s3-bucket-resource - # for more information about the S3 bucket refactor. - aws = { - source = "hashicorp/aws" - version = "~> 4.9" - } - } - - # We want to hold off on 1.1 or higher until we have tested it. - required_version = "~> 1.0" -} diff --git a/examples/basic_usage/vpc.tf b/examples/basic_usage/vpc.tf deleted file mode 100644 index 947e0eb..0000000 --- a/examples/basic_usage/vpc.tf +++ /dev/null @@ -1,20 +0,0 @@ -#------------------------------------------------------------------------------- -# Create a VPC -#------------------------------------------------------------------------------- - -resource "aws_vpc" "example" { - cidr_block = "10.230.0.0/24" - enable_dns_hostnames = true - tags = { "Name" : "Example" } -} - -#------------------------------------------------------------------------------- -# Create a subnet -#------------------------------------------------------------------------------- - -resource "aws_subnet" "example" { - availability_zone = "${var.aws_region}${var.aws_availability_zone}" - cidr_block = "10.230.0.0/28" - tags = { "Name" : "Example" } - vpc_id = aws_vpc.example.id -} diff --git a/main.tf b/main.tf deleted file mode 100644 index 0646a05..0000000 --- a/main.tf +++ /dev/null @@ -1,61 +0,0 @@ -# ------------------------------------------------------------------------------ -# Deploy the example AMI from cisagov/skeleton-packer in AWS. -# ------------------------------------------------------------------------------ - -# ------------------------------------------------------------------------------ -# Look up the latest example AMI from cisagov/skeleton-packer. -# -# NOTE: This Terraform data source must return at least one AMI result -# or the apply will fail. -# ------------------------------------------------------------------------------ - -# The AMI from cisagov/skeleton-packer -data "aws_ami" "example" { - filter { - name = "name" - values = [ - "example-hvm-*-x86_64-ebs", - ] - } - - filter { - name = "virtualization-type" - values = ["hvm"] - } - - filter { - name = "root-device-type" - values = ["ebs"] - } - - most_recent = true - owners = [ - var.ami_owner_account_id - ] -} - -# The default tags configured for the default provider -data "aws_default_tags" "default" {} - -# The example EC2 instance -resource "aws_instance" "example" { - ami = data.aws_ami.example.id - availability_zone = "${var.aws_region}${var.aws_availability_zone}" - instance_type = "t3.micro" - subnet_id = var.subnet_id - - # The tag or tags specified here will be merged with the provider's - # default tags. - tags = { - "Name" = "Example" - } - # volume_tags does not yet inherit the default tags from the - # provider. See hashicorp/terraform-provider-aws#19188 for more - # details. - volume_tags = merge( - data.aws_default_tags.default.tags, - { - "Name" = "Example" - }, - ) -} From dde2e5ecffa0ecf1caecd7440812ddda2088c3c4 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:08:47 -0400 Subject: [PATCH 02/26] Define initial providers --- providers.tf | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/providers.tf b/providers.tf index bc1ee01..194af06 100644 --- a/providers.tf +++ b/providers.tf @@ -1,13 +1,24 @@ -# This is an example of what a provider looks like. -# -# provider "aws" { -# alias = "myprovider" -# assume_role { -# role_arn = "arn:aws:iam::123456789012:role/MyRole" -# session_name = "MySessionName" -# } -# default_tags { -# tags = var.tags -# } -# region = var.aws_region -# } +# This is the "default" provider that is used to create resources +# inside the COOL CyHy account. +provider "aws" { + default_tags { + tags = var.tags + } + # Use this profile once the account has been bootstrapped. + profile = "cool-cyhy-provisionaccount" + # Use this profile, defined using programmatic credentials for + # AWSAdministratorAccess as obtained for the COOL CyHy account + # from the AWS SSO page, to bootstrap the account. + # profile = "cool-cyhy-account-admin" + region = var.aws_region +} + +# Read-only AWS Organizations provider +provider "aws" { + alias = "organizationsreadonly" + default_tags { + tags = var.tags + } + profile = "cool-master-organizationsreadonly" + region = var.aws_region +} From 772fc07fc5d0cc008fdf1d8fca71a07a36d992be Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:09:24 -0400 Subject: [PATCH 03/26] Define variables --- variables.tf | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/variables.tf b/variables.tf index 416ad14..6410913 100644 --- a/variables.tf +++ b/variables.tf @@ -1,33 +1,41 @@ # ------------------------------------------------------------------------------ -# REQUIRED PARAMETERS +# OPTIONAL PARAMETERS # -# You must provide a value for each of these parameters. +# These parameters have reasonable defaults. # ------------------------------------------------------------------------------ -variable "subnet_id" { - description = "The ID of the AWS subnet to deploy into (e.g. subnet-0123456789abcdef0)." +variable "aws_region" { + default = "us-east-1" + description = "The AWS region where the non-global resources for the Cyber Hygiene account are to be provisioned (e.g. \"us-east-1\")." type = string } -# ------------------------------------------------------------------------------ -# OPTIONAL PARAMETERS -# -# These parameters have reasonable defaults. -# ------------------------------------------------------------------------------ -variable "ami_owner_account_id" { - default = "self" - description = "The ID of the AWS account that owns the Example AMI, or \"self\" if the AMI is owned by the same account as the provisioner." +variable "provisionaccount_role_description" { + default = "Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." + description = "The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." type = string } -variable "aws_availability_zone" { - default = "a" - description = "The AWS availability zone to deploy into (e.g. a, b, c, etc.)." +variable "provisionaccount_role_name" { + default = "ProvisionAccount" + description = "The name to assign the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." type = string } -variable "aws_region" { - default = "us-east-1" - description = "The AWS region to deploy into (e.g. us-east-1)." +variable "provisionssmsessionmanager_policy_description" { + default = "Allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account." + description = "The description to associate with the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account." + type = string +} + +variable "provisionssmsessionmanager_policy_name" { + default = "ProvisionSSMSessionManager" + description = "The name to assign the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account." type = string } + +variable "tags" { + default = {} + description = "Tags to apply to all AWS resources provisioned." + type = map(string) +} From 5ea5074c01f2a4ba3862c126a3e64b60529baff4 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:09:59 -0400 Subject: [PATCH 04/26] Define backend --- backend.tf | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 backend.tf diff --git a/backend.tf b/backend.tf new file mode 100644 index 0000000..1c4814c --- /dev/null +++ b/backend.tf @@ -0,0 +1,10 @@ +terraform { + backend "s3" { + bucket = "cisa-cool-terraform-state" + dynamodb_table = "terraform-state-lock" + encrypt = true + key = "cool-accounts-cyhy/terraform.tfstate" + profile = "cool-terraform-backend" + region = "us-east-1" + } +} From be2d3823aabc32f57a55a67640500866cd1d9393 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:10:16 -0400 Subject: [PATCH 05/26] Define outputs --- outputs.tf | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/outputs.tf b/outputs.tf index ce18699..9eae919 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,24 +1,14 @@ -output "arn" { - description = "The EC2 instance ARN." - value = aws_instance.example.arn +output "cw_alarm_sns_topic" { + description = "The SNS topic to which a message is sent when a CloudWatch alarm is triggered." + value = module.cw_alarm_sns.sns_topic } -output "availability_zone" { - description = "The AZ where the EC2 instance is deployed." - value = aws_instance.example.availability_zone +output "provisionaccount_role" { + description = "The IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." + value = module.provisionaccount.provisionaccount_role } -output "id" { - description = "The EC2 instance ID." - value = aws_instance.example.id -} - -output "private_ip" { - description = "The private IP of the EC2 instance." - value = aws_instance.example.private_ip -} - -output "subnet_id" { - description = "The ID of the subnet where the EC2 instance is deployed." - value = aws_instance.example.subnet_id +output "ssm_session_role" { + description = "An IAM role that allows creation of SSM SessionManager sessions to any EC2 instance in this account." + value = module.session_manager.ssm_session_role } From 1862dc146e6bfb35a993496f2e1a4d3fff063885 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:10:43 -0400 Subject: [PATCH 06/26] Define locals --- locals.tf | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 locals.tf diff --git a/locals.tf b/locals.tf new file mode 100644 index 0000000..dfb25fa --- /dev/null +++ b/locals.tf @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------------ +# Retrieve the effective Account ID, User ID, and ARN in which Terraform is +# authorized. This is used to determine the CyHy account ID. +# ------------------------------------------------------------------------------ +data "aws_caller_identity" "cyhy" {} + +# Retrieve the information for all accounts in the organization. This is used, +# for instance, to lookup the account ID for the Users account. +data "aws_organizations_organization" "cool" { + provider = aws.organizationsreadonly +} + +# ------------------------------------------------------------------------------ +# Evaluate expressions for use throughout this configuration. +# ------------------------------------------------------------------------------ +locals { + # Find the Users account + users_account_id = [ + for account in data.aws_organizations_organization.cool.accounts : + account.id + if account.name == "Users" + ][0] + + # Get the CyHy account ID. + cyhy_account_id = data.aws_caller_identity.cyhy.id +} From 9d6fd65332fd3e5c56808923a1c6056a8aa3ed42 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:15:38 -0400 Subject: [PATCH 07/26] Create provisionaccount role --- provisionaccount.tf | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 provisionaccount.tf diff --git a/provisionaccount.tf b/provisionaccount.tf new file mode 100644 index 0000000..d36c80e --- /dev/null +++ b/provisionaccount.tf @@ -0,0 +1,7 @@ +module "provisionaccount" { + source = "github.com/cisagov/provisionaccount-role-tf-module" + + provisionaccount_role_description = var.provisionaccount_role_description + provisionaccount_role_name = var.provisionaccount_role_name + users_account_id = local.users_account_id +} From 748f41e199f4f561d9cf86e0f1699b30ef29ff3e Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:19:04 -0400 Subject: [PATCH 08/26] Provision SSM Session Manager --- provisionssmsessionmanager_policy.tf | 53 +++++++++++++++++++ ...sionssmsessionmanager_policy_attachment.tf | 10 ++++ session_manager.tf | 11 ++++ 3 files changed, 74 insertions(+) create mode 100644 provisionssmsessionmanager_policy.tf create mode 100644 provisionssmsessionmanager_policy_attachment.tf create mode 100644 session_manager.tf diff --git a/provisionssmsessionmanager_policy.tf b/provisionssmsessionmanager_policy.tf new file mode 100644 index 0000000..756428d --- /dev/null +++ b/provisionssmsessionmanager_policy.tf @@ -0,0 +1,53 @@ +# ------------------------------------------------------------------------------ +# Create the IAM policy that allows all of the permissions necessary to +# provision the SSM Document resource and set up SSM session logging in this +# account. +# ------------------------------------------------------------------------------ + +data "aws_iam_policy_document" "provisionssmsessionmanager_policy_doc" { + # SSM document permissions + statement { + actions = [ + "ssm:AddTagsToResource", + "ssm:CreateDocument", + "ssm:DeleteDocument", + "ssm:DescribeDocument*", + "ssm:GetDocument", + "ssm:UpdateDocument*", + ] + + resources = [ + "arn:aws:ssm:${var.aws_region}:${local.cyhy_account_id}:document/SSM-SessionManagerRunShell", + ] + } + + # CloudWatch log group permissions + statement { + actions = [ + "logs:CreateLogGroup", + "logs:DescribeLogGroups", + "logs:ListTagsLogGroup", + ] + + resources = [ + "*", + ] + } + statement { + actions = [ + "logs:DeleteLogGroup", + "logs:PutRetentionPolicy", + "logs:TagLogGroup", + ] + + resources = [ + "arn:aws:logs:${var.aws_region}:${local.cyhy_account_id}:log-group:${module.session_manager.ssm_session_log_group.name}:*", + ] + } +} + +resource "aws_iam_policy" "provisionssmsessionmanager_policy" { + description = var.provisionssmsessionmanager_policy_description + name = var.provisionssmsessionmanager_policy_name + policy = data.aws_iam_policy_document.provisionssmsessionmanager_policy_doc.json +} diff --git a/provisionssmsessionmanager_policy_attachment.tf b/provisionssmsessionmanager_policy_attachment.tf new file mode 100644 index 0000000..da257a2 --- /dev/null +++ b/provisionssmsessionmanager_policy_attachment.tf @@ -0,0 +1,10 @@ +# ------------------------------------------------------------------------------ +# Attach to the ProvisionAccount role the IAM policy that allows all of the +# permissions necessary to provision the SSM Document resource and set up SSM +# session logging in this account. +# ------------------------------------------------------------------------------ + +resource "aws_iam_role_policy_attachment" "provisionssmsessionmanager_policy_attachment" { + policy_arn = aws_iam_policy.provisionssmsessionmanager_policy.arn + role = module.provisionaccount.provisionaccount_role.name +} diff --git a/session_manager.tf b/session_manager.tf new file mode 100644 index 0000000..8a83b5f --- /dev/null +++ b/session_manager.tf @@ -0,0 +1,11 @@ +# ------------------------------------------------------------------------------ +# Provision SSM Session Manager and configure it for session logging. +# ------------------------------------------------------------------------------ + +module "session_manager" { + source = "github.com/cisagov/session-manager-tf-module" + + other_accounts = [ + local.users_account_id, + ] +} From 9c43abc50809619a7c050fb97badf06c78b631b0 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:19:46 -0400 Subject: [PATCH 09/26] Set up user modification alerting --- sns.tf | 15 ++++++++++ user-group-mod-notification.tf | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 sns.tf create mode 100644 user-group-mod-notification.tf diff --git a/sns.tf b/sns.tf new file mode 100644 index 0000000..b5852b7 --- /dev/null +++ b/sns.tf @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------------------ +# Create the SNS topic that allows email to be sent for CloudWatch +# alarms. Subscribe the account email to the new SNS topic. +# ------------------------------------------------------------------------------ + +module "cw_alarm_sns" { + providers = { + aws = aws + aws.organizations_read_only = aws.organizationsreadonly + } + source = "github.com/cisagov/sns-send-to-account-email-tf-module" + + topic_display_name = "cloudwatch_alarms" + topic_name = "cloudwatch-alarms" +} diff --git a/user-group-mod-notification.tf b/user-group-mod-notification.tf new file mode 100644 index 0000000..f1b29f7 --- /dev/null +++ b/user-group-mod-notification.tf @@ -0,0 +1,54 @@ +# ------------------------------------------------------------------------------ +# Create the SNS topic that allows email to be sent whenever a new IAM or SSO +# user is created or deleted, a user is added or removed from a group, or a +# group is created or deleted. Subscribe the account email to the new SNS +# topic. +# ------------------------------------------------------------------------------ + +data "aws_iam_policy_document" "sns_topic_access_policy_doc" { + # Allow EventBridge to publish to the SNS topic. + statement { + actions = [ + "sns:Publish", + ] + + principals { + identifiers = ["events.amazonaws.com"] + type = "Service" + } + + resources = [ + # We can't use module.user_group_mod_sns.sns_topic.arn here because it + # creates a cycle; fortunately, we can create the SNS topic ARN manually. + "arn:aws:sns:${var.aws_region}:${local.cyhy_account_id}:user-or-group-modified", + ] + } +} + +module "user_group_mod_sns" { + providers = { + aws = aws + aws.organizations_read_only = aws.organizationsreadonly + } + source = "github.com/cisagov/sns-send-to-account-email-tf-module" + + topic_access_policy = data.aws_iam_policy_document.sns_topic_access_policy_doc.json + topic_display_name = "IAM or SSO user or group modified" + topic_name = "user-or-group-modified" +} + +# ------------------------------------------------------------------------------ +# Create the EventBridge event rule that is triggered whenever a new IAM or SSO +# user is created or deleted, a user is added or removed from a group, or a +# group is created or deleted. Connect this rule to the SNS topic created +# above. +# ------------------------------------------------------------------------------ + +module "user_group_mod_event" { + providers = { + aws = aws + } + source = "github.com/cisagov/user-group-mod-alert-tf-module" + + target_arn = module.user_group_mod_sns.sns_topic.arn +} From a5ed87955d651f4606e0ae153bae5d0e32091771 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:20:14 -0400 Subject: [PATCH 10/26] Update README from skeleton --- README.md | 142 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 96c6c1d..1840677 100644 --- a/README.md +++ b/README.md @@ -2,33 +2,75 @@ [![GitHub Build Status](https://github.com/cisagov/cool-accounts-cyhy/workflows/build/badge.svg)](https://github.com/cisagov/cool-accounts-cyhy/actions) -This is a generic skeleton project that can be used to quickly get a -new [cisagov](https://github.com/cisagov) [Terraform -module](https://www.terraform.io/docs/modules/index.html) GitHub -repository started. This skeleton project contains [licensing -information](LICENSE), as well as [pre-commit -hooks](https://pre-commit.com) and -[GitHub Actions](https://github.com/features/actions) configurations -appropriate for the major languages that we use. - -See [here](https://www.terraform.io/docs/modules/index.html) for more -details on Terraform modules and the standard module structure. - -## Usage ## - -```hcl -module "example" { - source = "github.com/cisagov/cool-accounts-cyhy" - - aws_region = "us-west-1" - aws_availability_zone = "b" - subnet_id = "subnet-0123456789abcdef0" -} -``` - -## Examples ## - -- [Basic usage](https://github.com/cisagov/cool-accounts-cyhy/tree/develop/examples/basic_usage) +This project contains Terraform code to perform the initial configuration of a +COOL Cyber Hygiene (CyHy) account. This Terraform code creates and configures +the most basic resources needed to build out services and environments. + +It creates an IAM role that allows sufficient permissions to provision all AWS +resources in this account. This role has a trust relationship with the COOL +users account. + +## Bootstrapping this account ## + +Note that the COOL Cyber Hygiene account must be bootstrapped. This is because +initially there is no IAM role that can be assumed to build out these resources. +Therefore you must first apply the Terraform code using programmatic credentials +for AWSAdministratorAccess as obtained for the COOL Cyber Hygiene account from +the COOL AWS SSO page. + +After this initial apply your desired IAM role will exist, and it will be +assumable from your IAM user that exists in the COOL users account. Therefore +you can apply future changes using your IAM user credentials. + +To do this bootstrapping, follow these steps: + +1. Comment out the `profile = "cool-cyhy-provisionaccount"` line for the + "default" provider in `providers.tf` and directly below that uncomment the + line `profile = "cool-cyhy-account-admin"`. +1. Create a new AWS profile called `cool-cyhy-account-admin` in your local + configuration using the "AWSAdministratorAccess" credentials (access key ID, + secret access key, and session token) as obtained from the COOL Cyber Hygiene + account: + + ```ini + [cool-cyhy-account-admin] + aws_access_key_id = + aws_secret_access_key = + aws_session_token = + ``` + +1. Create a Terraform workspace (if you haven't already done so) by running + `terraform workspace new ` +1. Create a `.tfvars` file with any optional variables + that you wish to override (see [Inputs](#inputs) below for + details): + + ```hcl + tags = { + Team = "VM Fusion - Development" + Application = "COOL - Cyber Hygiene" + Workspace = "production" + } + ``` + +1. Run the command `terraform init`. +1. Run the command `terraform apply -var-file=.tfvars`. +1. Revert the changes you made to `providers.tf` in step 1. +1. Create a new AWS profile called `cool-cyhy-provisionaccount` in your local + configuration that includes the `provisionaccount_role` ARN output from the + previous step, for example: + + ```ini + [cool-cyhy-provisionaccount] + role_arn = arn:aws:iam::111111111111:role/ProvisionAccount + role_session_name = your.session.name + source_profile = cool-user-base-profile + ``` + +1. Run the command `terraform apply -var-file=.tfvars`. + +At this point the account has been bootstrapped, and you can apply future +changes by simply running `terraform apply -var-file=.tfvars`. ## Requirements ## @@ -43,51 +85,53 @@ module "example" { | Name | Version | |------|---------| | aws | ~> 4.9 | +| aws.organizationsreadonly | ~> 4.9 | ## Modules ## -No modules. +| Name | Source | Version | +|------|--------|---------| +| cw\_alarm\_sns | github.com/cisagov/sns-send-to-account-email-tf-module | n/a | +| provisionaccount | github.com/cisagov/provisionaccount-role-tf-module | n/a | +| session\_manager | github.com/cisagov/session-manager-tf-module | n/a | +| user\_group\_mod\_event | github.com/cisagov/user-group-mod-alert-tf-module | n/a | +| user\_group\_mod\_sns | github.com/cisagov/sns-send-to-account-email-tf-module | n/a | ## Resources ## | Name | Type | |------|------| -| [aws_instance.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | -| [aws_ami.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | -| [aws_default_tags.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/default_tags) | data source | +| [aws_iam_policy.provisionssmsessionmanager_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role_policy_attachment.provisionssmsessionmanager_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_caller_identity.cyhy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.provisionssmsessionmanager_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.sns_topic_access_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_organizations_organization.cool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | ## Inputs ## | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| ami\_owner\_account\_id | The ID of the AWS account that owns the Example AMI, or "self" if the AMI is owned by the same account as the provisioner. | `string` | `"self"` | no | -| aws\_availability\_zone | The AWS availability zone to deploy into (e.g. a, b, c, etc.). | `string` | `"a"` | no | -| aws\_region | The AWS region to deploy into (e.g. us-east-1). | `string` | `"us-east-1"` | no | -| subnet\_id | The ID of the AWS subnet to deploy into (e.g. subnet-0123456789abcdef0). | `string` | n/a | yes | +| aws\_region | The AWS region where the non-global resources for the Cyber Hygiene account are to be provisioned (e.g. "us-east-1"). | `string` | `"us-east-1"` | no | +| provisionaccount\_role\_description | The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account."` | no | +| provisionaccount\_role\_name | The name to assign the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"ProvisionAccount"` | no | +| provisionssmsessionmanager\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account."` | no | +| provisionssmsessionmanager\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"ProvisionSSMSessionManager"` | no | +| tags | Tags to apply to all AWS resources provisioned. | `map(string)` | `{}` | no | ## Outputs ## | Name | Description | |------|-------------| -| arn | The EC2 instance ARN. | -| availability\_zone | The AZ where the EC2 instance is deployed. | -| id | The EC2 instance ID. | -| private\_ip | The private IP of the EC2 instance. | -| subnet\_id | The ID of the subnet where the EC2 instance is deployed. | +| cw\_alarm\_sns\_topic | The SNS topic to which a message is sent when a CloudWatch alarm is triggered. | +| provisionaccount\_role | The IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | +| ssm\_session\_role | An IAM role that allows creation of SSM SessionManager sessions to any EC2 instance in this account. | ## Notes ## Running `pre-commit` requires running `terraform init` in every directory that -contains Terraform code. In this repository, these are the main directory and -every directory under `examples/`. - -## New Repositories from a Skeleton ## - -Please see our [Project Setup guide](https://github.com/cisagov/development-guide/tree/develop/project_setup) -for step-by-step instructions on how to start a new repository from -a skeleton. This will save you time and effort when configuring a -new repository! +contains Terraform code. In this repository, this is just the main directory. ## Contributing ## From 8efa88361de3b90d9136e011df45f5dee03d4fac Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 6 Sep 2024 11:21:31 -0400 Subject: [PATCH 11/26] Enable dependabot ignore directives --- .github/dependabot.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aa70e2e..b9e4b8e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,17 +29,17 @@ updates: interval: weekly - directory: / - # ignore: - # # Managed by cisagov/skeleton-tf-module - # - dependency-name: hashicorp/aws + ignore: + # Managed by cisagov/skeleton-tf-module + - dependency-name: hashicorp/aws package-ecosystem: terraform schedule: interval: weekly - directory: /examples/basic_usage - # ignore: - # # Managed by cisagov/skeleton-tf-module - # - dependency-name: hashicorp/aws + ignore: + # Managed by cisagov/skeleton-tf-module + - dependency-name: hashicorp/aws package-ecosystem: terraform schedule: interval: weekly From 11c059ec5a276acf47c3f68e00c867371c323dda Mon Sep 17 00:00:00 2001 From: David Redmin Date: Tue, 10 Sep 2024 16:14:04 -0400 Subject: [PATCH 12/26] Add variables related to the Lambda artifacts bucket --- variables.tf | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/variables.tf b/variables.tf index 6410913..ac90868 100644 --- a/variables.tf +++ b/variables.tf @@ -10,6 +10,12 @@ variable "aws_region" { type = string } +variable "lambda_artifacts_s3_bucket" { + default = "cool-cyhy-lambda-deployment-artifacts" + description = "The name of the bucket where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name." + type = string +} + variable "provisionaccount_role_description" { default = "Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." description = "The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." @@ -22,6 +28,18 @@ variable "provisionaccount_role_name" { type = string } +variable "provisionlambdabucket_policy_description" { + default = "Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." + description = "The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." + type = string +} + +variable "provisionlambdabucket_policy_name" { + default = "ProvisionLambdaArtifactsBucket" + description = "The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." + type = string +} + variable "provisionssmsessionmanager_policy_description" { default = "Allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account." description = "The description to associate with the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account." From aedfd7c9dfc363149e8a1d6f606d770fcf05fac7 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Tue, 10 Sep 2024 16:15:42 -0400 Subject: [PATCH 13/26] Add a local to determine the Lambda bucket name. --- locals.tf | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/locals.tf b/locals.tf index dfb25fa..b25f948 100644 --- a/locals.tf +++ b/locals.tf @@ -14,13 +14,22 @@ data "aws_organizations_organization" "cool" { # Evaluate expressions for use throughout this configuration. # ------------------------------------------------------------------------------ locals { + # Get the CyHy account ID. + cyhy_account_id = data.aws_caller_identity.cyhy.id + + # Determine if this is a Production workspace by checking if + # terraform.workspace begins with "prod" + production_workspace = length(regexall("^prod", terraform.workspace)) == 1 + + # In production Terraform workspaces, the string '-production' is appended to + # the bucket name. In non-production workspaces, '-' is + # appended to the bucket name. + lambda_bucket_name = format("%s-%s", var.lambda_artifacts_s3_bucket, local.production_workspace ? "production" : terraform.workspace) + # Find the Users account users_account_id = [ for account in data.aws_organizations_organization.cool.accounts : account.id if account.name == "Users" ][0] - - # Get the CyHy account ID. - cyhy_account_id = data.aws_caller_identity.cyhy.id } From a4aa9f968e0b31c644783f139fcaf50908db08c0 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Tue, 10 Sep 2024 16:20:45 -0400 Subject: [PATCH 14/26] Attach a policy to manage Lambda bucket creation, modification, deletion. --- provisionlambdabucket_policy.tf | 32 ++++++++++++++++++++++ provisionlambdabucket_policy_attachment.tf | 9 ++++++ 2 files changed, 41 insertions(+) create mode 100644 provisionlambdabucket_policy.tf create mode 100644 provisionlambdabucket_policy_attachment.tf diff --git a/provisionlambdabucket_policy.tf b/provisionlambdabucket_policy.tf new file mode 100644 index 0000000..a5dc868 --- /dev/null +++ b/provisionlambdabucket_policy.tf @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------------ +# Create the IAM policy that allows all of the permissions necessary to +# provision the Lambda deployment artifacts bucket. +# ------------------------------------------------------------------------------ + +data "aws_iam_policy_document" "provisionlambdabucket_policy_doc" { + statement { + actions = [ + "s3:CreateBucket", + "s3:DeleteBucket", + "s3:DeleteBucketPolicy", + "s3:Get*", + "s3:ListBucket", + "s3:PutBucketOwnershipControls", + "s3:PutBucketPolicy", + "s3:PutBucketPublicAccessBlock", + "s3:PutBucketTagging", + "s3:PutEncryptionConfiguration", + "s3:TagResource", + ] + + resources = [ + "arn:aws:s3:::${local.lambda_bucket_name}", + ] + } +} + +resource "aws_iam_policy" "provisionlambdabucket_policy" { + description = var.provisionlambdabucket_policy_description + name = var.provisionlambdabucket_policy_name + policy = data.aws_iam_policy_document.provisionlambdabucket_policy_doc.json +} diff --git a/provisionlambdabucket_policy_attachment.tf b/provisionlambdabucket_policy_attachment.tf new file mode 100644 index 0000000..d259b88 --- /dev/null +++ b/provisionlambdabucket_policy_attachment.tf @@ -0,0 +1,9 @@ +# ------------------------------------------------------------------------------ +# Attach to the ProvisionAccount role the IAM policy that allows provisioning of +# the Lambda deployment artifacts bucket. +# ------------------------------------------------------------------------------ + +resource "aws_iam_role_policy_attachment" "provisionlambdabucket_policy_attachment" { + policy_arn = aws_iam_policy.provisionlambdabucket_policy.arn + role = var.provisionaccount_role_name +} From cc8123e03731a56e0eca7a919310c8cb5f8ecc5b Mon Sep 17 00:00:00 2001 From: David Redmin Date: Tue, 10 Sep 2024 16:21:02 -0400 Subject: [PATCH 15/26] Define the Lambda bucket --- lambda_artifacts_bucket.tf | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 lambda_artifacts_bucket.tf diff --git a/lambda_artifacts_bucket.tf b/lambda_artifacts_bucket.tf new file mode 100644 index 0000000..33ec696 --- /dev/null +++ b/lambda_artifacts_bucket.tf @@ -0,0 +1,46 @@ +# This bucket is used to store the deployment packages for any Lambda functions +# that will be used in a CyHy environment. +resource "aws_s3_bucket" "lambda_artifacts" { + bucket = local.lambda_bucket_name + + tags = { + "Name" = "Lambda Deployment Artifacts" + } + + lifecycle { + prevent_destroy = true + } +} + +# Ensure the S3 bucket is encrypted +resource "aws_s3_bucket_server_side_encryption_configuration" "lambda_artifacts" { + bucket = aws_s3_bucket.lambda_artifacts.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +# This blocks ANY public access to the bucket or the objects it +# contains, even if misconfigured to allow public access. +resource "aws_s3_bucket_public_access_block" "lambda_artifacts" { + block_public_acls = true + block_public_policy = true + bucket = aws_s3_bucket.lambda_artifacts.id + ignore_public_acls = true + restrict_public_buckets = true +} + +# Any objects placed into this bucket should be owned by the bucket +# owner. This ensures that even if objects are added by a different +# account, the bucket-owning account retains full control over the +# objects stored in this bucket. +resource "aws_s3_bucket_ownership_controls" "lambda_artifacts" { + bucket = aws_s3_bucket.lambda_artifacts.id + + rule { + object_ownership = "BucketOwnerEnforced" + } +} From a25038d0586dc38216011ce38646c70f8e5cae04 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Tue, 10 Sep 2024 16:23:47 -0400 Subject: [PATCH 16/26] Update README to include bucket resources --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 1840677..d2a82dc 100644 --- a/README.md +++ b/README.md @@ -101,9 +101,16 @@ changes by simply running `terraform apply -var-file=.tfvars`. | Name | Type | |------|------| +| [aws_iam_policy.provisionlambdabucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.provisionssmsessionmanager_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role_policy_attachment.provisionlambdabucket_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.provisionssmsessionmanager_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_s3_bucket.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_ownership_controls.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | +| [aws_s3_bucket_public_access_block.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_server_side_encryption_configuration.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | | [aws_caller_identity.cyhy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.provisionlambdabucket_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.provisionssmsessionmanager_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.sns_topic_access_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_organizations_organization.cool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | @@ -113,8 +120,11 @@ changes by simply running `terraform apply -var-file=.tfvars`. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | aws\_region | The AWS region where the non-global resources for the Cyber Hygiene account are to be provisioned (e.g. "us-east-1"). | `string` | `"us-east-1"` | no | +| lambda\_artifacts\_s3\_bucket | The name of the bucket where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name. | `string` | `"cool-cyhy-lambda-deployment-artifacts"` | no | | provisionaccount\_role\_description | The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account."` | no | | provisionaccount\_role\_name | The name to assign the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"ProvisionAccount"` | no | +| provisionlambdabucket\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket. | `string` | `"Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket."` | no | +| provisionlambdabucket\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket. | `string` | `"ProvisionLambdaArtifactsBucket"` | no | | provisionssmsessionmanager\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account."` | no | | provisionssmsessionmanager\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"ProvisionSSMSessionManager"` | no | | tags | Tags to apply to all AWS resources provisioned. | `map(string)` | `{}` | no | From 7d78e8ec03786344c635133b10ff69205d9a3b2d Mon Sep 17 00:00:00 2001 From: David Redmin Date: Thu, 12 Sep 2024 09:43:19 -0400 Subject: [PATCH 17/26] Sort by Terraform arguments first, then sort by config blocks next This is a recent style pattern we have adopted. Co-authored-by: Jeremy Frasier --- user-group-mod-notification.tf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user-group-mod-notification.tf b/user-group-mod-notification.tf index f1b29f7..8b987cd 100644 --- a/user-group-mod-notification.tf +++ b/user-group-mod-notification.tf @@ -12,16 +12,16 @@ data "aws_iam_policy_document" "sns_topic_access_policy_doc" { "sns:Publish", ] - principals { - identifiers = ["events.amazonaws.com"] - type = "Service" - } - resources = [ # We can't use module.user_group_mod_sns.sns_topic.arn here because it # creates a cycle; fortunately, we can create the SNS topic ARN manually. "arn:aws:sns:${var.aws_region}:${local.cyhy_account_id}:user-or-group-modified", ] + + principals { + identifiers = ["events.amazonaws.com"] + type = "Service" + } } } From 7ad294f866ba9a4bcf14eaa1811ae24e5825bec6 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 13 Sep 2024 15:17:08 -0400 Subject: [PATCH 18/26] Add variables related to "disable inactive users" Lambda --- variables.tf | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/variables.tf b/variables.tf index ac90868..0d212f1 100644 --- a/variables.tf +++ b/variables.tf @@ -1,3 +1,19 @@ +# ------------------------------------------------------------------------------ +# REQUIRED PARAMETERS +# +# You must provide a value for each of these parameters. +# ------------------------------------------------------------------------------ + +variable "cool_lambda_artifacts_s3_bucket" { + description = "The name of the bucket where COOL Lambda deployment packages are to be stored." + type = string +} + +variable "disable_inactive_users_lambda_key" { + description = "The S3 key associated with the Lambda function deployment package to disable inactive IAM users." + type = string +} + # ------------------------------------------------------------------------------ # OPTIONAL PARAMETERS # @@ -52,6 +68,18 @@ variable "provisionssmsessionmanager_policy_name" { type = string } +variable "read_cool_lambda_bucket_policy_description" { + default = "Allows read-only access to the bucket in the Terraform account containing Lambda deployments." + description = "The description to associate with the IAM role that allows read-only access to the bucket in the Terraform account containing Lambda deployments." + type = string +} + +variable "read_cool_lambda_bucket_policy_name" { + default = "LambdaBucketReadOnly" + description = "The name to assign the IAM policy that allows read-only access to the bucket in the Terraform account containing Lambda deployments." + type = string +} + variable "tags" { default = {} description = "Tags to apply to all AWS resources provisioned." From 37ba3cde6930dc590f66be47186166ae233b2336 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 13 Sep 2024 15:19:27 -0400 Subject: [PATCH 19/26] Create policy allowing access to the COOL Lambda bucket and attach it to the CyHy ProvisionAccount role --- read_cool_lambda_bucket_policy.tf | 23 ++++++++++++++++++++ read_cool_lambda_bucket_policy_attachment.tf | 10 +++++++++ 2 files changed, 33 insertions(+) create mode 100644 read_cool_lambda_bucket_policy.tf create mode 100644 read_cool_lambda_bucket_policy_attachment.tf diff --git a/read_cool_lambda_bucket_policy.tf b/read_cool_lambda_bucket_policy.tf new file mode 100644 index 0000000..e15bcae --- /dev/null +++ b/read_cool_lambda_bucket_policy.tf @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------------ +# Create the IAM policy that allows all of the permissions necessary +# to read from the bucket containing the COOL Lambda deployments. +# ------------------------------------------------------------------------------ + +data "aws_iam_policy_document" "read_cool_lambda_bucket_policy_doc" { + statement { + actions = [ + "s3:GetObject", + "s3:ListBucket", + ] + resources = [ + "arn:aws:s3:::${var.cool_lambda_artifacts_s3_bucket}", + "arn:aws:s3:::${var.cool_lambda_artifacts_s3_bucket}/*" + ] + } +} + +resource "aws_iam_policy" "read_cool_lambda_bucket_policy" { + description = var.read_cool_lambda_bucket_policy_description + name = var.read_cool_lambda_bucket_policy_name + policy = data.aws_iam_policy_document.read_cool_lambda_bucket_policy_doc.json +} diff --git a/read_cool_lambda_bucket_policy_attachment.tf b/read_cool_lambda_bucket_policy_attachment.tf new file mode 100644 index 0000000..7a42601 --- /dev/null +++ b/read_cool_lambda_bucket_policy_attachment.tf @@ -0,0 +1,10 @@ +# ------------------------------------------------------------------------------ +# Attach to the ProvisionAccount role the IAM policy that allows reading from +# the S3 bucket in the Terraform account where Lambda deployment packages are +# stored. +# ------------------------------------------------------------------------------ + +resource "aws_iam_role_policy_attachment" "read_cool_lambda_bucket" { + policy_arn = aws_iam_policy.read_cool_lambda_bucket_policy.arn + role = module.provisionaccount.provisionaccount_role.name +} From 1fda0dd49b4a19e5d244f7dd78aa0d5ba778dd07 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 13 Sep 2024 15:20:52 -0400 Subject: [PATCH 20/26] Add module to disable inactive users --- disable-inactive-iam-users.tf | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 disable-inactive-iam-users.tf diff --git a/disable-inactive-iam-users.tf b/disable-inactive-iam-users.tf new file mode 100644 index 0000000..0f5e15b --- /dev/null +++ b/disable-inactive-iam-users.tf @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------------ +# Create the EventBridge event rule that triggers at a fixed cadence, kicking +# off a Lambda function that disables inactive IAM users. +# ------------------------------------------------------------------------------ +module "disable-inactive-iam-users" { + depends_on = [ + aws_iam_role_policy_attachment.read_cool_lambda_bucket, + ] + providers = { + aws = aws + } + + source = "github.com/cisagov/disable-inactive-iam-users-tf-module" + + lambda_bucket_name = var.cool_lambda_artifacts_s3_bucket + lambda_key = var.disable_inactive_users_lambda_key +} From e4b7ba32f9a9eb0a2e64ca7cbe57155036dc5f54 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 13 Sep 2024 15:22:36 -0400 Subject: [PATCH 21/26] Improve some variable names and descriptions --- locals.tf | 2 +- variables.tf | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/locals.tf b/locals.tf index b25f948..7589a07 100644 --- a/locals.tf +++ b/locals.tf @@ -24,7 +24,7 @@ locals { # In production Terraform workspaces, the string '-production' is appended to # the bucket name. In non-production workspaces, '-' is # appended to the bucket name. - lambda_bucket_name = format("%s-%s", var.lambda_artifacts_s3_bucket, local.production_workspace ? "production" : terraform.workspace) + lambda_bucket_name = format("%s-%s", var.cyhy_lambda_artifacts_s3_bucket, local.production_workspace ? "production" : terraform.workspace) # Find the Users account users_account_id = [ diff --git a/variables.tf b/variables.tf index 0d212f1..012a24e 100644 --- a/variables.tf +++ b/variables.tf @@ -26,9 +26,9 @@ variable "aws_region" { type = string } -variable "lambda_artifacts_s3_bucket" { +variable "cyhy_lambda_artifacts_s3_bucket" { default = "cool-cyhy-lambda-deployment-artifacts" - description = "The name of the bucket where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name." + description = "The name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name." type = string } @@ -45,14 +45,14 @@ variable "provisionaccount_role_name" { } variable "provisionlambdabucket_policy_description" { - default = "Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." - description = "The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." + default = "Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account." + description = "The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account." type = string } variable "provisionlambdabucket_policy_name" { default = "ProvisionLambdaArtifactsBucket" - description = "The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket." + description = "The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account." type = string } From b4fe6c55ac3af9ed7c4ace6208dd300396833067 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 13 Sep 2024 15:25:04 -0400 Subject: [PATCH 22/26] Update Terraform docs in README --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d2a82dc..3048691 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ changes by simply running `terraform apply -var-file=.tfvars`. | Name | Source | Version | |------|--------|---------| | cw\_alarm\_sns | github.com/cisagov/sns-send-to-account-email-tf-module | n/a | +| disable-inactive-iam-users | github.com/cisagov/disable-inactive-iam-users-tf-module | n/a | | provisionaccount | github.com/cisagov/provisionaccount-role-tf-module | n/a | | session\_manager | github.com/cisagov/session-manager-tf-module | n/a | | user\_group\_mod\_event | github.com/cisagov/user-group-mod-alert-tf-module | n/a | @@ -103,8 +104,10 @@ changes by simply running `terraform apply -var-file=.tfvars`. |------|------| | [aws_iam_policy.provisionlambdabucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.provisionssmsessionmanager_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.read_cool_lambda_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_role_policy_attachment.provisionlambdabucket_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.provisionssmsessionmanager_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.read_cool_lambda_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_s3_bucket.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | | [aws_s3_bucket_ownership_controls.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | | [aws_s3_bucket_public_access_block.lambda_artifacts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | @@ -112,6 +115,7 @@ changes by simply running `terraform apply -var-file=.tfvars`. | [aws_caller_identity.cyhy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_iam_policy_document.provisionlambdabucket_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.provisionssmsessionmanager_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.read_cool_lambda_bucket_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.sns_topic_access_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_organizations_organization.cool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | @@ -120,13 +124,17 @@ changes by simply running `terraform apply -var-file=.tfvars`. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | aws\_region | The AWS region where the non-global resources for the Cyber Hygiene account are to be provisioned (e.g. "us-east-1"). | `string` | `"us-east-1"` | no | -| lambda\_artifacts\_s3\_bucket | The name of the bucket where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name. | `string` | `"cool-cyhy-lambda-deployment-artifacts"` | no | +| cool\_lambda\_artifacts\_s3\_bucket | The name of the bucket where COOL Lambda deployment packages are to be stored. | `string` | n/a | yes | +| cyhy\_lambda\_artifacts\_s3\_bucket | The name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name. | `string` | `"cool-cyhy-lambda-deployment-artifacts"` | no | +| disable\_inactive\_users\_lambda\_key | The S3 key associated with the Lambda function deployment package to disable inactive IAM users. | `string` | n/a | yes | | provisionaccount\_role\_description | The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account."` | no | | provisionaccount\_role\_name | The name to assign the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"ProvisionAccount"` | no | -| provisionlambdabucket\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket. | `string` | `"Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket."` | no | -| provisionlambdabucket\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket. | `string` | `"ProvisionLambdaArtifactsBucket"` | no | +| provisionlambdabucket\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account."` | no | +| provisionlambdabucket\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the Lambda deployment artifacts S3 bucket in the Cyber Hygiene account. | `string` | `"ProvisionLambdaArtifactsBucket"` | no | | provisionssmsessionmanager\_policy\_description | The description to associate with the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account."` | no | | provisionssmsessionmanager\_policy\_name | The name to assign the IAM policy that allows sufficient permissions to provision the SSM Document resource and set up SSM session logging in the Cyber Hygiene account. | `string` | `"ProvisionSSMSessionManager"` | no | +| read\_cool\_lambda\_bucket\_policy\_description | The description to associate with the IAM role that allows read-only access to the bucket in the Terraform account containing Lambda deployments. | `string` | `"Allows read-only access to the bucket in the Terraform account containing Lambda deployments."` | no | +| read\_cool\_lambda\_bucket\_policy\_name | The name to assign the IAM policy that allows read-only access to the bucket in the Terraform account containing Lambda deployments. | `string` | `"LambdaBucketReadOnly"` | no | | tags | Tags to apply to all AWS resources provisioned. | `map(string)` | `{}` | no | ## Outputs ## From 0ab516dd30bfcf723fa02b9fb6a0e7756ffe0a70 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Wed, 18 Sep 2024 15:11:05 -0400 Subject: [PATCH 23/26] Remove an outdated team name from an example in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3048691..1154fac 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ To do this bootstrapping, follow these steps: ```hcl tags = { - Team = "VM Fusion - Development" + Team = "VM - Development" Application = "COOL - Cyber Hygiene" Workspace = "production" } From eb4cd5125c066678ddefbfdacc113febd8df0050 Mon Sep 17 00:00:00 2001 From: David Redmin Date: Fri, 20 Sep 2024 17:03:28 -0400 Subject: [PATCH 24/26] Add a pre-requisites section to the README Co-authored-by: mcdonnnj --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 1154fac..9c37219 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,18 @@ It creates an IAM role that allows sufficient permissions to provision all AWS resources in this account. This role has a trust relationship with the COOL users account. +## Pre-requisites ## + +- [Terraform](https://www.terraform.io/) installed on your system. +- An accessible AWS S3 bucket to store Terraform state (specified in + [backend.tf](backend.tf)). +- An accessible AWS DynamoDB database to store the Terraform state lock + (specified in [backend.tf](backend.tf)). + +We recommend creating the S3 bucket and DynamoDB table above by applying the +Terraform code in the "terraform" subdirectory of +[`cisagov/cool-accounts`](https://github.com/cisagov/cool-accounts). + ## Bootstrapping this account ## Note that the COOL Cyber Hygiene account must be bootstrapped. This is because From 7944880cb81a26e58f23c13a581f3827960f401e Mon Sep 17 00:00:00 2001 From: David Redmin Date: Mon, 23 Sep 2024 11:11:05 -0400 Subject: [PATCH 25/26] Create CyHy Lambda artifacts bucket name using bucket_prefix This makes our bucket names unique and allows us to remove some local variables that are no longer needed. Co-authored-by: Nicholas McDonnell <50747025+mcdonnnj@users.noreply.github.com> Co-authored-by: Jeremy Frasier --- README.md | 2 +- lambda_artifacts_bucket.tf | 2 +- locals.tf | 9 --------- provisionlambdabucket_policy.tf | 2 +- variables.tf | 4 ++-- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 9c37219..07b888f 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ changes by simply running `terraform apply -var-file=.tfvars`. |------|-------------|------|---------|:--------:| | aws\_region | The AWS region where the non-global resources for the Cyber Hygiene account are to be provisioned (e.g. "us-east-1"). | `string` | `"us-east-1"` | no | | cool\_lambda\_artifacts\_s3\_bucket | The name of the bucket where COOL Lambda deployment packages are to be stored. | `string` | n/a | yes | -| cyhy\_lambda\_artifacts\_s3\_bucket | The name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name. | `string` | `"cool-cyhy-lambda-deployment-artifacts"` | no | +| cyhy\_lambda\_artifacts\_s3\_bucket\_prefix | The prefix of the name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. A unique bucket name beginning with the specified prefix will be created. | `string` | `"cool-cyhy-lambda-deployment-artifacts"` | no | | disable\_inactive\_users\_lambda\_key | The S3 key associated with the Lambda function deployment package to disable inactive IAM users. | `string` | n/a | yes | | provisionaccount\_role\_description | The description to associate with the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"Allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account."` | no | | provisionaccount\_role\_name | The name to assign the IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | `string` | `"ProvisionAccount"` | no | diff --git a/lambda_artifacts_bucket.tf b/lambda_artifacts_bucket.tf index 33ec696..af7e1b8 100644 --- a/lambda_artifacts_bucket.tf +++ b/lambda_artifacts_bucket.tf @@ -1,7 +1,7 @@ # This bucket is used to store the deployment packages for any Lambda functions # that will be used in a CyHy environment. resource "aws_s3_bucket" "lambda_artifacts" { - bucket = local.lambda_bucket_name + bucket_prefix = var.cyhy_lambda_artifacts_s3_bucket_prefix tags = { "Name" = "Lambda Deployment Artifacts" diff --git a/locals.tf b/locals.tf index 7589a07..221ecc0 100644 --- a/locals.tf +++ b/locals.tf @@ -17,15 +17,6 @@ locals { # Get the CyHy account ID. cyhy_account_id = data.aws_caller_identity.cyhy.id - # Determine if this is a Production workspace by checking if - # terraform.workspace begins with "prod" - production_workspace = length(regexall("^prod", terraform.workspace)) == 1 - - # In production Terraform workspaces, the string '-production' is appended to - # the bucket name. In non-production workspaces, '-' is - # appended to the bucket name. - lambda_bucket_name = format("%s-%s", var.cyhy_lambda_artifacts_s3_bucket, local.production_workspace ? "production" : terraform.workspace) - # Find the Users account users_account_id = [ for account in data.aws_organizations_organization.cool.accounts : diff --git a/provisionlambdabucket_policy.tf b/provisionlambdabucket_policy.tf index a5dc868..c66cd10 100644 --- a/provisionlambdabucket_policy.tf +++ b/provisionlambdabucket_policy.tf @@ -20,7 +20,7 @@ data "aws_iam_policy_document" "provisionlambdabucket_policy_doc" { ] resources = [ - "arn:aws:s3:::${local.lambda_bucket_name}", + "arn:aws:s3:::${var.cyhy_lambda_artifacts_s3_bucket_prefix}*", ] } } diff --git a/variables.tf b/variables.tf index 012a24e..2688f93 100644 --- a/variables.tf +++ b/variables.tf @@ -26,9 +26,9 @@ variable "aws_region" { type = string } -variable "cyhy_lambda_artifacts_s3_bucket" { +variable "cyhy_lambda_artifacts_s3_bucket_prefix" { default = "cool-cyhy-lambda-deployment-artifacts" - description = "The name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. Note that in production Terraform workspaces, the string '-production' will be appended to the bucket name. In non-production workspaces, '-' will be appended to the bucket name." + description = "The prefix of the name of the bucket in the Cyber Hygiene account where any Lambda deployment artifacts for a CyHy environment will be stored. A unique bucket name beginning with the specified prefix will be created." type = string } From 6ce0814b6450cb567c9f99bcbb2dded1cf9d851f Mon Sep 17 00:00:00 2001 From: David Redmin Date: Mon, 23 Sep 2024 11:12:35 -0400 Subject: [PATCH 26/26] Add an output for the Lambda artifacts bucket Co-authored-by: Nicholas McDonnell <50747025+mcdonnnj@users.noreply.github.com> --- README.md | 1 + outputs.tf | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 07b888f..b700e88 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ changes by simply running `terraform apply -var-file=.tfvars`. | Name | Description | |------|-------------| | cw\_alarm\_sns\_topic | The SNS topic to which a message is sent when a CloudWatch alarm is triggered. | +| lambda\_artifacts\_bucket | The S3 bucket in the Cyber Hygiene account where Lambda artifacts are stored. | | provisionaccount\_role | The IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account. | | ssm\_session\_role | An IAM role that allows creation of SSM SessionManager sessions to any EC2 instance in this account. | diff --git a/outputs.tf b/outputs.tf index 9eae919..5d62c78 100644 --- a/outputs.tf +++ b/outputs.tf @@ -3,6 +3,11 @@ output "cw_alarm_sns_topic" { value = module.cw_alarm_sns.sns_topic } +output "lambda_artifacts_bucket" { + description = "The S3 bucket in the Cyber Hygiene account where Lambda artifacts are stored." + value = aws_s3_bucket.lambda_artifacts +} + output "provisionaccount_role" { description = "The IAM role that allows sufficient permissions to provision all AWS resources in the Cyber Hygiene account." value = module.provisionaccount.provisionaccount_role