Skip to content

Commit

Permalink
Least privilege module (#48)
Browse files Browse the repository at this point in the history
* add variables and infra for least privilege analytics

* update bucket config

* update env vars

* fix acl

* fix outputs

* fix bool interpretation

* fix bool env var

* update env var

* add required AWS IAM IDC read permission

* update ALB path rule

* add assume role external ID

* widen assume role scope

* remove duplicate variable

* fix provisioner iam policy

* fix duplicate resource names

* fix iam policies and count conditions

* changeset

* Update .changeset/polite-falcons-sleep.md

---------

Co-authored-by: chrnorm <[email protected]>
  • Loading branch information
JoshuaWilkes and chrnorm authored Feb 19, 2024
1 parent 714a2c3 commit 47d06e6
Show file tree
Hide file tree
Showing 19 changed files with 539 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/polite-falcons-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@common-fate/terraform-aws-common-fate-deployment": minor
---

Adds modules required for Least Privilege Analysis.
125 changes: 70 additions & 55 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -77,65 +77,80 @@ module "control_plane" {
namespace = var.namespace
stage = var.stage

aws_region = var.aws_region
aws_account_id = data.aws_caller_identity.current.account_id
aws_partition = data.aws_partition.current.id
database_secret_sm_arn = module.control_plane_db.secret_arn
database_security_group_id = module.control_plane_db.security_group_id
eventbus_arn = module.events.event_bus_arn
sqs_queue_arn = module.events.sqs_queue_arn
app_url = var.app_url
pager_duty_client_id = var.pager_duty_client_id
pager_duty_client_secret_ps_arn = var.pager_duty_client_secret_ps_arn
release_tag = var.release_tag
scim_source = var.scim_source
scim_token_ps_arn = var.scim_token_ps_arn
slack_client_id = var.slack_client_id
slack_client_secret_ps_arn = var.slack_client_secret_ps_arn
slack_signing_secret_ps_arn = var.slack_signing_secret_ps_arn
subnet_ids = module.vpc.private_subnet_ids
vpc_id = module.vpc.vpc_id
ecs_cluster_id = module.ecs.cluster_id
auth_authority_url = module.cognito.auth_authority_url
database_host = module.control_plane_db.endpoint
database_user = module.control_plane_db.username
alb_listener_arn = module.alb.listener_arn
sqs_queue_name = module.events.sqs_queue_name
auth_issuer = module.cognito.auth_issuer
control_plane_service_client_id = module.cognito.control_plane_service_client_id
control_plane_service_client_secret = module.cognito.control_plane_service_client_secret
licence_key_ps_arn = var.licence_key_ps_arn
log_level = var.control_plane_log_level
grant_assume_on_role_arns = var.control_plane_grant_assume_on_role_arns
oidc_control_plane_issuer = module.cognito.auth_issuer
otel_log_group_name = module.ecs_base.otel_log_group_name
otel_writer_iam_policy_arn = module.ecs_base.otel_writer_iam_policy_arn
alb_security_group_id = module.alb.alb_security_group_id
additional_cors_allowed_origins = var.additional_cors_allowed_origins
assume_role_external_id = var.assume_role_external_id
aws_region = var.aws_region
aws_account_id = data.aws_caller_identity.current.account_id
aws_partition = data.aws_partition.current.id
database_secret_sm_arn = module.control_plane_db.secret_arn
database_security_group_id = module.control_plane_db.security_group_id
eventbus_arn = module.events.event_bus_arn
sqs_queue_arn = module.events.sqs_queue_arn
app_url = var.app_url
pager_duty_client_id = var.pager_duty_client_id
pager_duty_client_secret_ps_arn = var.pager_duty_client_secret_ps_arn
release_tag = var.release_tag
scim_source = var.scim_source
scim_token_ps_arn = var.scim_token_ps_arn
slack_client_id = var.slack_client_id
slack_client_secret_ps_arn = var.slack_client_secret_ps_arn
slack_signing_secret_ps_arn = var.slack_signing_secret_ps_arn
subnet_ids = module.vpc.private_subnet_ids
vpc_id = module.vpc.vpc_id
ecs_cluster_id = module.ecs.cluster_id
auth_authority_url = module.cognito.auth_authority_url
database_host = module.control_plane_db.endpoint
database_user = module.control_plane_db.username
alb_listener_arn = module.alb.listener_arn
sqs_queue_name = module.events.sqs_queue_name
auth_issuer = module.cognito.auth_issuer
control_plane_service_client_id = module.cognito.control_plane_service_client_id
control_plane_service_client_secret = module.cognito.control_plane_service_client_secret
licence_key_ps_arn = var.licence_key_ps_arn
log_level = var.control_plane_log_level
grant_assume_on_role_arns = var.control_plane_grant_assume_on_role_arns
oidc_control_plane_issuer = module.cognito.auth_issuer
otel_log_group_name = module.ecs_base.otel_log_group_name
otel_writer_iam_policy_arn = module.ecs_base.otel_writer_iam_policy_arn
alb_security_group_id = module.alb.alb_security_group_id
additional_cors_allowed_origins = var.additional_cors_allowed_origins
unstable_enable_feature_least_privilege = var.unstable_enable_feature_least_privilege
unstable_least_privilege_analysis_schedule = var.unstable_least_privilege_analysis_schedule
unstable_sync_idc_cloudtrail_schedule = var.unstable_sync_idc_cloudtrail_schedule
report_bucket_arn = module.report_bucket.arn
report_bucket_name = module.report_bucket.id
assume_role_external_id = var.assume_role_external_id
}

module "report_bucket" {
source = "./modules/s3bucket"
bucket_prefix = "${var.namespace}-${var.stage}-reports"
aws_account_id = data.aws_caller_identity.current.account_id
region = var.aws_region
namespace = var.namespace
stage = var.stage
component = "reports"
}

module "web" {
source = "./modules/web"
namespace = var.namespace
stage = var.stage
aws_region = var.aws_region
release_tag = var.release_tag
subnet_ids = module.vpc.private_subnet_ids
vpc_id = module.vpc.vpc_id
auth_authority_url = module.cognito.auth_authority_url
auth_cli_client_id = module.cognito.cli_client_id
auth_url = var.auth_url
auth_web_client_id = module.cognito.web_client_id
logo_url = var.logo_url
team_name = var.team_name
ecs_cluster_id = module.ecs.cluster_id
alb_listener_arn = module.alb.listener_arn
app_url = var.app_url
auth_issuer = module.cognito.auth_issuer
alb_security_group_id = module.alb.alb_security_group_id

module "web" {
source = "./modules/web"
namespace = var.namespace
stage = var.stage
aws_region = var.aws_region
release_tag = var.release_tag
subnet_ids = module.vpc.private_subnet_ids
vpc_id = module.vpc.vpc_id
auth_authority_url = module.cognito.auth_authority_url
auth_cli_client_id = module.cognito.cli_client_id
auth_url = var.auth_url
auth_web_client_id = module.cognito.web_client_id
logo_url = var.logo_url
team_name = var.team_name
ecs_cluster_id = module.ecs.cluster_id
alb_listener_arn = module.alb.listener_arn
app_url = var.app_url
auth_issuer = module.cognito.auth_issuer
alb_security_group_id = module.alb.alb_security_group_id
unstable_enable_feature_least_privilege = var.unstable_enable_feature_least_privilege
}

module "access_handler" {
Expand Down
52 changes: 49 additions & 3 deletions modules/controlplane/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,34 @@ resource "aws_iam_role_policy_attachment" "otel" {
policy_arn = var.otel_writer_iam_policy_arn
}

resource "aws_iam_policy" "report_bucket" {
name = "${var.namespace}-${var.stage}-control-plane-reports"
description = "Allows the Control Plane to read and write from the Report S3 bucket"

policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Sid" : "ListObjectsInBucket",
"Effect" : "Allow",
"Action" : ["s3:ListBucket"],
"Resource" : [var.report_bucket_arn]
},
{
"Sid" : "AllObjectActions",
"Effect" : "Allow",
"Action" : "s3:*Object",
"Resource" : ["${var.report_bucket_arn}/*"]
}
]
})
}

resource "aws_iam_role_policy_attachment" "control_plane_report_bucket_attach" {
role = aws_iam_role.control_plane_ecs_task_role.name
policy_arn = aws_iam_policy.report_bucket.arn
}

resource "aws_iam_policy" "eventbus_put_events" {
name = "${var.namespace}-${var.stage}-control-plane-eb"
description = "Allows ECS tasks to put events to the event bus"
Expand All @@ -170,10 +198,12 @@ resource "aws_iam_policy" "eventbus_put_events" {
]
})
}

resource "aws_iam_role_policy_attachment" "control_plane_eventbus_put_events_attach" {
role = aws_iam_role.control_plane_ecs_task_role.name
policy_arn = aws_iam_policy.eventbus_put_events.arn
}

resource "aws_iam_policy" "sqs_subscribe" {
name = "${var.namespace}-${var.stage}-control-plane-sqs"
description = "Allows access to read sqs queue and delete messages"
Expand Down Expand Up @@ -411,9 +441,25 @@ resource "aws_ecs_task_definition" "control_plane_task" {
value = "0 */5 * * * *"
},
{
name = "CF_ASSUME_ROLE_EXTERNAL_ID"
value = var.assume_role_external_id
name = "CF_FEATURE_LEAST_PRIVILEGE_ENABLED",
value = var.unstable_enable_feature_least_privilege ? "true" : "false"
},
{
name = "CF_SYNC_IDC_CLOUDTRAIL_CRON_SCHEDULE",
value = var.unstable_sync_idc_cloudtrail_schedule
},
{
name = "CF_LEAST_PRIVILEGE_ANALYSIS_CRON_SCHEDULE",
value = var.unstable_least_privilege_analysis_schedule
},
{
name = "CF_REPORT_S3_BUCKET",
value = var.report_bucket_name
},
{
name = "CF_ASSUME_ROLE_EXTERNAL_ID",
value = var.assume_role_external_id
}
],

// Only add these secrets if their values are provided
Expand Down Expand Up @@ -536,7 +582,7 @@ resource "aws_lb_listener_rule" "service_rule" {
}
condition {
path_pattern {
values = ["/commonfate.control*", "/api/*"]
values = ["/commonfate.control*", "/api/*", "/commonfate.leastprivilege*"]
}
}
}
32 changes: 31 additions & 1 deletion modules/controlplane/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,38 @@ variable "additional_cors_allowed_origins" {
description = "Additional origins to add to the CORS allowlist. By default, the app URL is automatically added."
}


variable "unstable_enable_feature_least_privilege" {
type = bool
default = false
description = "Opt-in to enable Least Privilege Analytics (in early access). This variable will be removed once the feature is released."
}

variable "unstable_sync_idc_cloudtrail_schedule" {
type = string
default = "0 13 0 * * *"
description = "Least Privilege Analytics: the schedule to sync AWS CloudTrail events on"
}

variable "unstable_least_privilege_analysis_schedule" {
type = string
default = "0 13 5 * * *"
description = "Least Privilege Analytics: the schedule to build least privilege reports on"
}

variable "report_bucket_arn" {
type = string
description = "ARN of report bucket"
}

variable "report_bucket_name" {
type = string
description = "Name of report bucket"
}


variable "assume_role_external_id" {
description = "(Optional) The external id to be used when assuming IAM roles"
description = "(Optional) External ID to use when assuming cross-account AWS roles for auditing and provisioning."
type = string
default = ""
}
Expand Down
34 changes: 34 additions & 0 deletions modules/s3bucket/data_iam_policy_document.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
data "aws_iam_policy_document" "main" {
source_policy_documents = var.policy_documents

statement {
sid = "DontAllowNonSecureConnection"
effect = "Deny"

actions = [
"s3:*",
]

resources = [
aws_s3_bucket.main.arn,
"${aws_s3_bucket.main.arn}/*",
]

principals {
type = "AWS"

identifiers = [
"*",
]
}

condition {
test = "Bool"
variable = "aws:SecureTransport"

values = [
"false",
]
}
}
}
37 changes: 37 additions & 0 deletions modules/s3bucket/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
locals {
# Compound Scope Identifier
csi = replace(
format(
"%s-%s-%s-%s",
var.namespace,
var.stage,
var.component,
var.bucket_prefix,
),
"_",
"",
)

# CSI for use in resources with a global namespace, i.e. S3 Buckets
csi_global = replace(
format(
"%s-%s-%s-%s-%s-%s",
var.namespace,
var.aws_account_id,
var.region,
var.stage,
var.component,
var.bucket_prefix,
),
"_",
"",
)

default_tags = merge(
var.default_tags,
{
Module = var.module
Name = var.bucket_prefix
},
)
}
31 changes: 31 additions & 0 deletions modules/s3bucket/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
output "arn" {
value = aws_s3_bucket.main.arn
}

output "bucket" {
value = aws_s3_bucket.main.bucket
}

output "bucket_domain_name" {
value = aws_s3_bucket.main.bucket_domain_name
}

output "bucket_regional_domain_name" {
value = aws_s3_bucket.main.bucket_regional_domain_name
}

output "hosted_zone_id" {
value = aws_s3_bucket.main.hosted_zone_id
}

output "id" {
value = aws_s3_bucket.main.id
}

output "policy" {
value = aws_s3_bucket_policy.main.policy
}

output "region" {
value = aws_s3_bucket.main.region
}
6 changes: 6 additions & 0 deletions modules/s3bucket/s3_bucket.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "aws_s3_bucket" "main" {
bucket_prefix = var.bucket_prefix
force_destroy = var.force_destroy

tags = local.default_tags
}
Loading

0 comments on commit 47d06e6

Please sign in to comment.