Skip to content

Commit

Permalink
Merge pull request #37 from Crown-Commercial-Service/ithc-ingress-wit…
Browse files Browse the repository at this point in the history
…hout-rds

Creating ITHC Ingress without RDS module
  • Loading branch information
pasipa2 authored Jan 5, 2024
2 parents 2269e38 + 534375f commit 2aaa896
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 0 deletions.
39 changes: 39 additions & 0 deletions modules/ithc-ingress-without-rds-caution/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ITHC Ingress - Caution!

This module introduces resources which deliberately bypass and / or reduce the efficacy of existing security measures.

It's intended for use during an IT Health Check / Penetration Test situation.

> You are **STRONGLY** advised never to use this module in production.
## Adding Ingress in your project

This module is designed to be reusable and temporary. To optimise on both these attributes it's advised to implement it as follows:

### Locate the module invocation separately

Invoke the module using the typical Terraform `module` construct.

It's advised to put this block into the top-level of your environment folder, as a separate file with a name such as `ithc_ingress.tf` (so, for example, `environments/staging/ithc_ingress.tf`). There are a few reasons for this approach:

1. It shows with a glance of the folder that this environment has ITHC ingress set up
2. It stops the `main.tf` becoming cluttered
3. When you are finished testing, each of the resources and components can be removed from your platform by simply deleting this file and re-applying the Terraform.

## What gets created

This module adds the following:

* An IAM user for ITHC audit (the ARN for this is in the module outputs)
* An IAM group for ITHC audit - the audit user is placed into this group and the group has policies:
* ReadOnlyAccess
* SecurityAudit
* A custom policy as defined in [this file](ithc_iam_user.tf) which allows key management, MFA management, etc and blocks SSM access (among other things)
* An EC2 instance for VPC Scanning (the public DNS name for this is in the module outputs, and the username to use for ssh connection is `kali`)

## Origins

Adopted from:

* https://github.com/Crown-Commercial-Service/ccs-corporate-website-terraform/tree/main/cgi_ithc
* https://github.com/Crown-Commercial-Service/ccs-digital-foundation-terraform/tree/main/cgi_ithc
108 changes: 108 additions & 0 deletions modules/ithc-ingress-without-rds-caution/ithc_iam_user.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
resource "aws_iam_user" "ithc_audit" {
name = "${var.resource_name_prefixes.hyphens_lower}-ithc-audit"
}

resource "aws_iam_group" "ithc_audit" {
name = "${var.resource_name_prefixes.hyphens_lower}-ithc-audit"
}

resource "aws_iam_user_group_membership" "ithc_audit" {
groups = [
aws_iam_group.ithc_audit.name
]
user = aws_iam_user.ithc_audit.name
}

resource "aws_iam_group_policy_attachment" "ithc_audit__read_only_access" {
group = aws_iam_group.ithc_audit.name
policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

resource "aws_iam_group_policy_attachment" "ithc_audit__security_audit" {
group = aws_iam_group.ithc_audit.name
policy_arn = "arn:aws:iam::aws:policy/SecurityAudit"
}

data "aws_iam_policy_document" "custom_ithc_access_rules" {
statement {
sid = "AllowAccessKeyManagement"
effect = "Allow"
actions = [
"iam:DeleteAccessKey",
"iam:UpdateAccessKey",
"iam:CreateAccessKey",
"iam:ListAccessKeys"
]
resources = [
"arn:aws:iam::*:user/$${aws:username}"
]
}

statement {
sid = "AllowManageOwnVirtualMFADevice"
effect = "Allow"
actions = [
"iam:DeleteVirtualMFADevice",
"iam:CreateVirtualMFADevice",
]
resources = [
"arn:aws:iam::*:mfa/$${aws:username}"
]
}

statement {
sid = "AllowManageOwnUserMFA"
effect = "Allow"
actions = [
"iam:ResyncMFADevice",
"iam:ListMFADevices",
"iam:EnableMFADevice",
"iam:DeactivateMFADevice",
]
resources = [
"arn:aws:iam::*:user/$${aws:username}"
]
}

statement {
sid = "BlockMostAccessUnlessSignedInWithMFA"
effect = "Deny"
condition {
test = "Bool"
values = [false]
variable = "aws:MultiFactorAuthPresent"
}
not_actions = [
"sts:GetSessionToken",
"iam:ResyncMFADevice",
"iam:ListVirtualMFADevices",
"iam:ListUsers",
"iam:ListServiceSpecificCredentials",
"iam:ListSSHPublicKeys",
"iam:ListMFADevices",
"iam:ListAccountAliases",
"iam:ListAccessKeys",
"iam:GetAccountSummary",
"iam:EnableMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:CreateVirtualMFADevice",
]
resources = ["*"]
}

statement {
sid = "DenyAllSSMAccess"
effect = "Deny"
actions = [
"ssm:GetParameter*"
]
resources = [
"arn:aws:ssm:*:*:*"
]
}
}

resource "aws_iam_group_policy" "ithc_audit__custom_rules" {
group = aws_iam_group.ithc_audit.name
policy = data.aws_iam_policy_document.custom_ithc_access_rules.json
}
14 changes: 14 additions & 0 deletions modules/ithc-ingress-without-rds-caution/network_acls.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Override existing NACL - For rules on overriding see:
# https://github.com/Crown-Commercial-Service/ccs-migration-alpha-tools/tree/main/modules/four-tier-vpc#network-acls-and-customisation-of
#
resource "aws_network_acl_rule" "public__allow_ssh_everywhere_in" {
for_each = toset(var.ithc_operative_cidr_safelist)
cidr_block = each.value
egress = false
from_port = 22
network_acl_id = var.public_subnets_nacl_id
protocol = "tcp"
rule_action = "allow"
rule_number = index(var.ithc_operative_cidr_safelist, each.value) + 1
to_port = 22
}
9 changes: 9 additions & 0 deletions modules/ithc-ingress-without-rds-caution/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "ithc_audit_iam_user_arn" {
description = "ARN of the IAM user created for ITHC audit"
value = aws_iam_user.ithc_audit.arn
}

output "vpc_scanner_public_dns" {
description = "Public DNS name of the VPC Scanner instance"
value = aws_instance.vpc_scanner.public_dns
}
8 changes: 8 additions & 0 deletions modules/ithc-ingress-without-rds-caution/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">=5.26.0"
}
}
}
50 changes: 50 additions & 0 deletions modules/ithc-ingress-without-rds-caution/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# See naming convention doc:
# https://crowncommercialservice.atlassian.net/wiki/spaces/GPaaS/pages/3561685032/AWS+3+Tier+Reference+Architecture
variable "ithc_operative_cidr_safelist" {
type = list(string)
description = "List of CIDR ranges to be allowed to access the EC2 instances"
}

variable "public_subnets_nacl_id" {
type = string
description = "The ID of the existing NACL for public subnets"
}

variable "resource_name_prefixes" {
type = object({
normal = string,
hyphens = string,
hyphens_lower = string,
})
description = "Prefix to apply to resources in AWS; options provided to satisfy divergent naming requirements across AWS"
}

variable "vpc_cidr_block" {
type = string
description = "CIDR block of the VPC"
}

variable "vpc_id" {
type = string
description = "The ID of the VPC"
}

variable "vpc_scanner_instance_public_key" {
type = string
description = "Single-line public key (e.g. 'ssh-ed25519 AAAAver3rbrbr')"
}

variable "vpc_scanner_instance_root_device_size_gb" {
type = number
description = "Required size in GB of the root device for the VPC Scanner instance"
}

variable "vpc_scanner_instance_subnet_id" {
type = string
description = "ID of the subnet for the VPC Scanner instance - probably a public one"
}

variable "vpc_scanner_instance_type" {
type = string
description = "Instance type for the VPC Scanner instance"
}
107 changes: 107 additions & 0 deletions modules/ithc-ingress-without-rds-caution/vpc_scanner_instance.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Instance used to scan for vulnerabilities from inside the VPC.
#
resource "aws_key_pair" "vpc_scanner" {
key_name = "${var.resource_name_prefixes.hyphens_lower}-vpc-scanner"
public_key = var.vpc_scanner_instance_public_key
}

data "aws_ami" "kali_pinned_ami" {
most_recent = true

filter {
name = "name"
values = ["kali-last-snapshot-amd64-2023.3.0-804fcc46-63fc-4eb6-85a1-50e66d6c7215"]
}

owners = [
"aws-marketplace"
]
}

resource "aws_instance" "vpc_scanner" {
associate_public_ip_address = true
ami = data.aws_ami.kali_pinned_ami.id
instance_type = var.vpc_scanner_instance_type
key_name = aws_key_pair.vpc_scanner.key_name
subnet_id = var.vpc_scanner_instance_subnet_id
vpc_security_group_ids = [
aws_security_group.vpc_scanner_instance.id,
]

root_block_device {
encrypted = true
volume_size = var.vpc_scanner_instance_root_device_size_gb
}

tags = {
"Name" = "${var.resource_name_prefixes.normal}:EC2:VPCSCAN"
}
}

resource "aws_security_group" "vpc_scanner_instance" {
name = "${var.resource_name_prefixes.normal}:EC2:VPCSCAN"
description = "EC2 instance for VPC scanning"
vpc_id = var.vpc_id

tags = {
Name = "${var.resource_name_prefixes.normal}:EC2:VPCSCAN"
}
}

resource "aws_security_group_rule" "vpc_scanner_instance_ssh_in" {
cidr_blocks = var.ithc_operative_cidr_safelist
description = "Allow SSH from approved ranges into the VPC Scanner instance"
from_port = 22
protocol = "tcp"
security_group_id = aws_security_group.vpc_scanner_instance.id
to_port = 22
type = "ingress"
}

resource "aws_security_group_rule" "vpc_scanner_http_anywhere_out" {
cidr_blocks = [
"0.0.0.0/0",
]
description = "Allows HTTP to anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
security_group_id = aws_security_group.vpc_scanner_instance.id
type = "egress"
}

resource "aws_security_group_rule" "vpc_scanner_https_anywhere_out" {
cidr_blocks = [
"0.0.0.0/0",
]
description = "Allows HTTPS to anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
security_group_id = aws_security_group.vpc_scanner_instance.id
type = "egress"
}

resource "aws_security_group_rule" "vpc_scanner_all_tcp_vpc_out" {
cidr_blocks = [
var.vpc_cidr_block
]
description = "Any TCP within VPC"
from_port = 0
to_port = 65535
protocol = "tcp"
security_group_id = aws_security_group.vpc_scanner_instance.id
type = "egress"
}

resource "aws_security_group_rule" "vpc_scanner_all_udp_vpc_out" {
cidr_blocks = [
var.vpc_cidr_block
]
description = "Any UDP within VPC"
from_port = 0
to_port = 65535
protocol = "udp"
security_group_id = aws_security_group.vpc_scanner_instance.id
type = "egress"
}

0 comments on commit 2aaa896

Please sign in to comment.