Skip to content

Commit

Permalink
Bastion logging (#66)
Browse files Browse the repository at this point in the history
* added and tested managed node group

Signed-off-by: jase koonce <[email protected]>

* rebasing

Signed-off-by: jase koonce <[email protected]>

* pre-commit

Signed-off-by: jase koonce <[email protected]>

* bastion logging wip

Signed-off-by: jase koonce <[email protected]>

* adding eventbridge rules to aggregate logs

Signed-off-by: jase koonce <[email protected]>

* tested/adjusted formating

Signed-off-by: jase koonce <[email protected]>

* rebase

Signed-off-by: jase koonce <[email protected]>

* WIP

Signed-off-by: jase koonce <[email protected]>

* adds username logging/one concurrent session

Signed-off-by: jase koonce <[email protected]>

* cleanup/precommit

Signed-off-by: jase koonce <[email protected]>

* add parameters to example modules and update readmes (#84)

* make optional

* update readme

* update env vars

* unable to iterate over tuple if it doesn't exist

* default null

* parameterize instance type

* refactor

* add

* parameterize instance type

* parameterize instance type

* update readme

* parameterize

* add parameters to example

* add backend.tf.example

* update lockfile thing

* add backend.tf.example

* DRYify admin username parameters

* update variables

* DRYify input vars

* add -foce-copy

* Remove variable, do not need defaults at the moment

* added cluster_name

* update readmes

* updating self-managed/managed readmes

Signed-off-by: jase koonce <[email protected]>

* fix some pah and var logic

* update readme

* ignore build dir

* update readme

* Empty commit

* testing sign

* testing sign again

* testing sign again again

* update readme

* update env vars

* unable to iterate over tuple if it doesn't exist

* default null

* parameterize instance type

* refactor

* add

* parameterize instance type

* parameterize instance type

* update readme

* Move the tfstate-backend module to its own repo (#77)

* Update README.md (#78)

* Use new remote tfstate-backend module (and delete the one in this repo) (#80)

* eks output fix (#83)

* parameterize

* add parameters to example

* add backend.tf.example

* update lockfile thing

* add backend.tf.example

* DRYify admin username parameters

* update variables

* DRYify input vars

* add -foce-copy

* Remove variable, do not need defaults at the moment

* added cluster_name

* update readmes

* fix some pah and var logic

* update readme

* update readme

* updating self-managed/managed readmes

Signed-off-by: jase koonce <[email protected]>

* Empty commit

* testing sign

* testing sign again

* testing sign again again

---------

Signed-off-by: jase koonce <[email protected]>
Co-authored-by: jase koonce <[email protected]>
Co-authored-by: Andy Roth <[email protected]>
Co-authored-by: Gabe <[email protected]>

* Update CODEOWNERS to use groups (#87)

* Add GitHub Actions workflows for enabling test automation (#86)

* change kc db output from endpoint to address (#92)

* added and tested managed node group

Signed-off-by: jase koonce <[email protected]>

* rebase

Signed-off-by: jase koonce <[email protected]>

* Fixing cloudwatch error

Signed-off-by: jase koonce <[email protected]>

* adjusting userdata to log out newest session

Signed-off-by: jase koonce <[email protected]>

* Fixing failed checks

Signed-off-by: jase koonce <[email protected]>

* bastion refactor

Signed-off-by: jase koonce <[email protected]>

* adding newline for checks

Signed-off-by: jase koonce <[email protected]>

* add checkov comments/adjust startup script behavior

Signed-off-by: jase koonce <[email protected]>

* formating adjustment

Signed-off-by: jase koonce <[email protected]>

---------

Signed-off-by: jase koonce <[email protected]>
Co-authored-by: Gabe <[email protected]>
Co-authored-by: brian.rexrode <[email protected]>
Co-authored-by: Zack A <[email protected]>
Co-authored-by: Andy Roth <[email protected]>
Co-authored-by: brianrexrode <[email protected]>
  • Loading branch information
6 people authored Mar 9, 2023
1 parent 2df059f commit 667ba9c
Show file tree
Hide file tree
Showing 7 changed files with 593 additions and 52 deletions.
9 changes: 8 additions & 1 deletion modules/bastion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ No modules.

| Name | Type |
|------|------|
| [aws_cloudtrail.ssh-access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudtrail) | resource |
| [aws_cloudwatch_event_rule.ssh-access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
| [aws_cloudwatch_event_target.ssm-target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
| [aws_cloudwatch_log_group.ec2_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_cloudwatch_log_group.session_manager_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_cloudwatch_log_group.ssh-access-log-group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_iam_instance_profile.bastion_ssm_profile](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_policy.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.s3_logging_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
Expand All @@ -56,14 +61,14 @@ No modules.
| [aws_network_interface_attachment.attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface_attachment) | resource |
| [aws_s3_bucket.access_log_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket.session_logs_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket_acl.access_log_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl) | resource |
| [aws_s3_bucket_acl.session_logs_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl) | resource |
| [aws_s3_bucket_lifecycle_configuration.access_log_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
| [aws_s3_bucket_lifecycle_configuration.session_logs_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
| [aws_s3_bucket_logging.access_logging_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |
| [aws_s3_bucket_logging.session_logs_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |
| [aws_s3_bucket_notification.access_log_bucket_notification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification) | resource |
| [aws_s3_bucket_notification.session_logs_bucket_notification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification) | resource |
| [aws_s3_bucket_policy.cloudwatch-s3-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
| [aws_s3_bucket_public_access_block.access_log_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
| [aws_s3_bucket_public_access_block.session_logs_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
| [aws_s3_bucket_server_side_encryption_configuration.access_log_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
Expand All @@ -73,10 +78,12 @@ No modules.
| [aws_security_group.sg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_sqs_queue.queue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | resource |
| [aws_ssm_document.session_manager_prefs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_document) | resource |
| [aws_ssm_parameter.cloudwatch_configuration_file](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource |
| [tls_private_key.bastion_key](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
| [aws_ami.from_filter](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy.AmazonSSMManagedInstanceCore](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source |
| [aws_iam_policy_document.cloudwatch-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.kms_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.ssm_ec2_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.ssm_s3_cwl_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
Expand Down
57 changes: 56 additions & 1 deletion modules/bastion/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ data "aws_iam_policy" "AmazonSSMManagedInstanceCore" {
arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonSSMManagedInstanceCore"
}


resource "aws_iam_role_policy_attachment" "bastion-ssm-amazon-policy-attach" {
role = aws_iam_role.bastion_ssm_role.name
policy_arn = data.aws_iam_policy.AmazonSSMManagedInstanceCore.arn
Expand Down Expand Up @@ -129,7 +130,7 @@ data "aws_iam_policy_document" "ssm_ec2_access" {
]
}
}

# Create a custom policy for the bastion and attachment
resource "aws_iam_policy" "ssm_ec2_access" {
name = "ssm-${var.name}-${var.aws_region}"
path = "/"
Expand Down Expand Up @@ -393,3 +394,57 @@ resource "aws_iam_policy" "terraform_policy" {
}
EOF
}
# Create custom policy for KMS
data "aws_iam_policy_document" "kms_access" {
# checkov:skip=CKV_AWS_111: todo reduce perms on key
# checkov:skip=CKV_AWS_109: todo be more specific with resources
statement {
sid = "KMS Key Default"
principals {
type = "AWS"
identifiers = [
"arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"
]
}

actions = [
"kms:*",
]

resources = ["*"]
}
statement {
sid = "CloudWatchLogsEncryption"
principals {
type = "Service"
identifiers = ["logs.${var.aws_region}.amazonaws.com"]
}
actions = [
"kms:Encrypt*",
"kms:Decrypt*",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Describe*",
]

resources = ["*"]
}
statement {
sid = "Cloudtrail KMS permissions"
principals {
type = "Service"
identifiers = [
"cloudtrail.amazonaws.com"
]
}
actions = [
"kms:Encrypt*",
"kms:Decrypt*",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Describe*",
]
resources = ["*"]
}

}
171 changes: 171 additions & 0 deletions modules/bastion/logging.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Create a log group for ssh accesss
resource "aws_cloudwatch_log_group" "ssh-access-log-group" {
name = "/aws/events/ssh-access"
retention_in_days = 60
kms_key_id = aws_kms_key.ssmkey.arn
}

# Create a cloudtrail and event rule to monitor bastion access over ssh
resource "aws_cloudtrail" "ssh-access" {
# checkov:skip=CKV_AWS_252: SNS not currently needed
# checkov:skip=CKV2_AWS_10: Cloudwatch logs already being used with cloudtrail
name = "ssh-access"
s3_bucket_name = var.access_log_bucket_name
kms_key_id = aws_kms_key.ssmkey.arn
is_multi_region_trail = true
enable_log_file_validation = true
event_selector {
read_write_type = "All"
include_management_events = true
}
depends_on = [
aws_s3_bucket_policy.cloudwatch-s3-policy,
aws_kms_key.ssmkey,
aws_cloudwatch_log_group.ssh-access-log-group
]
}

resource "aws_cloudwatch_event_rule" "ssh-access" {
name = "ssh-access"
description = "filters ssm access logs and sends usable data to a cloudwatch log group"

event_pattern = <<EOF
{
"source": ["aws.ssm"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ssm.amazonaws.com"],
"eventName": ["IAMUser","StartSession"]
}
}
EOF
}

resource "aws_cloudwatch_event_target" "ssm-target" {
rule = aws_cloudwatch_event_rule.ssh-access.name
target_id = "ssh-access-target"
arn = aws_cloudwatch_log_group.ssh-access-log-group.arn
}

# Create a cloudwatch agent configuration file and log group
resource "aws_ssm_parameter" "cloudwatch_configuration_file" {
name = "AmazonCloudWatch-linux-${var.name}"
type = "SecureString"
overwrite = true
value = jsonencode({
"agent" : {
"metrics_collection_interval" : 60,
"run_as_user" : "root"
},
"logs" : {
"logs_collected" : {
"files" : {
"collect_list" : [
{
"file_path" : "/root/.bash_history",
"log_group_name" : "ec2-cloudwatch-logging-${var.name}",
"log_stream_name" : "root-user-commands",
"retention_in_days" : 60
},
{
"file_path" : "/home/ec2-user/.bash_history",
"log_group_name" : "ec2-cloudwatch-logging-${var.name}",
"log_stream_name" : "ec2-user-commands",
"retention_in_days" : 60
},

{
"file_path" : "/var/log/secure",
"log_group_name" : "ec2-cloudwatch-logging-${var.name}",
"log_stream_name" : "logins",
"retention_in_days" : 60
},
{
"file_path" : "/home/ssm-user/.bash_history",
"log_group_name" : "ec2-cloudwatch-logging-${var.name}",
"log_stream_name" : "ssm-user-commands",
"retention_in_days" : 60
},
]
}
}
},
"metrics" : {
"aggregation_dimensions" : [
[
"InstanceId"
]
],

"metrics_collected" : {
"collectd" : {
"metrics_aggregation_interval" : 60
},
"cpu" : {
"measurement" : [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval" : 60,
"resources" : [
"*"
],
"totalcpu" : false
},
"disk" : {
"measurement" : [
"used_percent",
"inodes_free"
],
"metrics_collection_interval" : 60,
"resources" : [
"*"
]
},
"diskio" : {
"measurement" : [
"io_time"
],
"metrics_collection_interval" : 60,
"resources" : [
"*"
]
},
"mem" : {
"measurement" : [
"mem_used_percent"
],
"metrics_collection_interval" : 60
},
"statsd" : {
"metrics_aggregation_interval" : 60,
"metrics_collection_interval" : 10,
"service_address" : ":8125"
},
"swap" : {
"measurement" : [
"swap_used_percent"
],
"metrics_collection_interval" : 60
}
}
}
})
}

resource "aws_cloudwatch_log_group" "ec2_cloudwatch_logs" {
name = "ec2-cloudwatch-logging-${var.name}"
retention_in_days = 60
kms_key_id = aws_kms_key.ssmkey.arn
}

# Create cloudwatch log group for ssm
resource "aws_cloudwatch_log_group" "session_manager_log_group" {
name_prefix = "${var.cloudwatch_log_group_name}-"
retention_in_days = var.cloudwatch_logs_retention
kms_key_id = aws_kms_key.ssmkey.arn

tags = var.tags
}
2 changes: 2 additions & 0 deletions modules/bastion/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ data "cloudinit_config" "config" {

part {
content_type = "text/x-shellscript"

content = templatefile("${path.module}/templates/user_data.sh.tpl",
{
s3_bucket_name = aws_s3_bucket.access_log_bucket.id // var.s3_bucket_name
Expand All @@ -201,6 +202,7 @@ data "cloudinit_config" "config" {
ssm_enabled = var.ssm_enabled
ssh_password = var.ssh_password
zarf_version = var.zarf_version
ssm_parameter_name = var.name
}
)
}
Expand Down
75 changes: 70 additions & 5 deletions modules/bastion/s3-buckets.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,81 @@
# Create S3 bucket for access logs with versioning, encryption, blocked public acess enabled
resource "aws_s3_bucket" "access_log_bucket" {
# checkov:skip=CKV_AWS_144: Cross region replication is overkill
bucket_prefix = "${var.access_log_bucket_name}-"

bucket = var.access_log_bucket_name
force_destroy = true
tags = var.tags
}
data "aws_iam_policy_document" "cloudwatch-policy" {

statement {
sid = "AWSCloudTrailAclCheck"
effect = "Allow"

principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}

actions = [
"s3:GetBucketAcl",
]

resources = [
"arn:aws:s3:::${var.access_log_bucket_name}",
]

condition {
test = "StringEquals"
variable = "AWS:SourceArn"

values = [
"arn:aws:cloudtrail:${var.aws_region}:${data.aws_caller_identity.current.account_id}:trail/ssh-access",
]
}
}

tags = var.tags
statement {
sid = "AWSCloudTrailWrite"
effect = "Allow"

principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}

actions = [
"s3:PutObject",
]

resources = [
"arn:aws:s3:::${var.access_log_bucket_name}/*",
]

condition {
test = "StringEquals"
variable = "s3:x-amz-acl"

values = [
"bucket-owner-full-control",
]
}

condition {
test = "StringEquals"
variable = "AWS:SourceArn"

values = [
"arn:aws:cloudtrail:${var.aws_region}:${data.aws_caller_identity.current.account_id}:trail/ssh-access",
]
}
}
}

resource "aws_s3_bucket_acl" "access_log_bucket" {
bucket = aws_s3_bucket.access_log_bucket.id
resource "aws_s3_bucket_policy" "cloudwatch-s3-policy" {
bucket = aws_s3_bucket.access_log_bucket.bucket
policy = data.aws_iam_policy_document.cloudwatch-policy.json

acl = "log-delivery-write"
}

resource "aws_s3_bucket_versioning" "access_log_bucket" {
Expand Down
Loading

0 comments on commit 667ba9c

Please sign in to comment.