diff --git a/README.md b/README.md index 1c8c28b..6523fda 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,13 @@ # opencti-terraform ## Before you deploy -Before you get going, there are a few things you will need to do: -- Edit `main.tf`: - - (optional) Edit the AWS region (default is `us-east-1`). - - Make sure your AWS credentials are in place and edit the path to them. - - Edit the login e-mail (`opencti_install_email`). - - Edit the `vpc_id`. - - Edit the `subnet_id` -- In `security_group.tf`: - - Add your public-facing IP address to the ingress rules (this can be a comma-separated list). -- (optional) In `ec2.tf`: - - Edit the instance's tag `Name` (the default is "opencti"). +Before you get going, there are a some variables you will probably want to set. All of these can be found in `aws/terraform.tfvars`: +- `allowed_ips_application`: Array containing each of the IPs that are allowed to access the web application. Default `0.0.0.0/0` all IPs. +- `availability_zone`: The AWS availability zone. Default `us-east-1a`. +- `login_email`: The e-mail address used to login to the application. Default `login.email@example.com`. +- `region`: The AWS region used. Default `us-east`. +- `root_volume_size`: The root volume size for the EC2 instance. Without this, the volume is 7.7GB and fills up in a day. Default `32` (GB). Note that this will incur costs. +- `subnet_id`: The AWS subnet to use. No default specified. +- `vpc_id`: The VPC to use. No default specified. ## Deployment To deploy, navigate to the repository and run `terraform init`. Then, create a plan (`terraform plan`) and check it over. Once you're good to go, apply it (`terraform apply`). diff --git a/ec2.tf b/aws/ec2.tf similarity index 52% rename from ec2.tf rename to aws/ec2.tf index 535a32d..dd249a8 100644 --- a/ec2.tf +++ b/aws/ec2.tf @@ -1,21 +1,24 @@ # EC2 Instance -resource "aws_instance" "test" { +resource "aws_instance" "opencti_instance" { ami = local.ami_id instance_type = local.instance_type - # Default VPC subnet for NC Sandbox - subnet_id = local.subnet_id associate_public_ip_address = true - iam_instance_profile = aws_iam_instance_profile.opencti-profile.name + iam_instance_profile = aws_iam_instance_profile.opencti_profile.name + root_block_device { + volume_size = var.root_volume_size + } + subnet_id = var.subnet_id - user_data = templatefile("./userdata/installation-wrapper-script.sh", { + user_data = templatefile("../userdata/installation-wrapper-script.sh", { + login_email = var.login_email, opencti_bucket_name = local.opencti_bucket_name, - opencti_install_email = local.opencti_install_email, + opencti_dir = local.opencti_dir, opencti_install_script_name = local.opencti_install_script_name, opencti_connectors_script_name = local.opencti_connectors_script_name }) - vpc_security_group_ids = [aws_security_group.opencti.id] + vpc_security_group_ids = [aws_security_group.opencti_sg.id] tags = { Name = "opencti" diff --git a/aws/iam.tf b/aws/iam.tf new file mode 100644 index 0000000..9fc83f5 --- /dev/null +++ b/aws/iam.tf @@ -0,0 +1,42 @@ +# IAM initial config +resource "aws_iam_role" "opencti_role" { + name = "opencti_role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) +} + +resource "aws_iam_instance_profile" "opencti_profile" { + name = "opencti_profile" + role = aws_iam_role.opencti_role.name +} + +# AWS Systems Manager (SSM) +data "aws_iam_policy" "ssm" { + arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" +} + +resource "aws_iam_role_policy_attachment" "opencti_ssm_attach" { + role = aws_iam_role.opencti_role.name + policy_arn = data.aws_iam_policy.ssm.arn +} + +# S3 +data "aws_iam_policy" "s3readonly" { + arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" +} + +resource "aws_iam_role_policy_attachment" "opencti_readonly_attach" { + role = aws_iam_role.opencti_role.name + policy_arn = data.aws_iam_policy.s3readonly.arn +} diff --git a/aws/main.tf b/aws/main.tf new file mode 100644 index 0000000..d05c26f --- /dev/null +++ b/aws/main.tf @@ -0,0 +1,15 @@ +provider "aws" { + region = var.region + shared_credentials_file = "~/.aws/credentials" + profile = "default" +} + +# These variables aren't meant to be changed by the end user. +locals { + ami_id = "ami-0074ee617a234808d" # Ubuntu 20.04 LTS + instance_type = "t3.2xlarge" # 8x32 with EBS-backed storage + opencti_bucket_name = "opencti-storage" + opencti_dir = "/opt/opencti" + opencti_install_script_name = "opencti-installer.sh" + opencti_connectors_script_name = "opencti-connectors.sh" +} diff --git a/aws/network.tf b/aws/network.tf new file mode 100644 index 0000000..8c020bd --- /dev/null +++ b/aws/network.tf @@ -0,0 +1,28 @@ +# This code creates a VPC and Subnet. The code applies just fine. But Systems Manager (SSM) is unusable. Says something isn't right. Been tracking it down for far too long and it's outside the scope of this change anyway so commenting and moving along. This VPC/Subnet issue is tracked in #9. +# resource "aws_vpc" "opencti_vpc" { +# cidr_block = "10.1.0.0/16" + +# tags = { +# Name = "OpenCTI VPC" +# } +# } + +# resource "aws_subnet" "opencti_subnet" { +# vpc_id = aws_vpc.opencti_vpc.id +# cidr_block = "10.1.10.0/24" +# availability_zone = var.availability_zone + +# tags = { +# Name = "OpenCTI subnet" +# } +# } + +# resource "aws_network_interface" "opencti_nic" { +# subnet_id = aws_subnet.opencti_subnet.id +# # private_ips = ["10.1.10.100"] +# security_groups = [ aws_security_group.opencti_sg.id ] + +# tags = { +# Name = "primary_network_interface" +# } +# } diff --git a/aws/security_group.tf b/aws/security_group.tf new file mode 100644 index 0000000..5941222 --- /dev/null +++ b/aws/security_group.tf @@ -0,0 +1,25 @@ +# Security group +resource "aws_security_group" "opencti_sg" { + name = "opencti_sg" + vpc_id = var.vpc_id + + ingress { + description = "Allow access to application on port 4000" + from_port = 4000 + to_port = 4000 + protocol = "tcp" + cidr_blocks = var.allowed_ips_application + } + + egress { + description = "Application can send outbound traffic to these IPs" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "opencti security group" + } +} diff --git a/aws/storage.tf b/aws/storage.tf new file mode 100644 index 0000000..c0155cf --- /dev/null +++ b/aws/storage.tf @@ -0,0 +1,43 @@ +# S3 bucket to store install and connectors scripts. +resource "aws_s3_bucket" "opencti_bucket" { + bucket = local.opencti_bucket_name + acl = "private" +} + +# S3 IAM (I don't think any of these permissions are being used) +data "aws_iam_policy_document" "opencti_s3" { + statement { + actions = [ + "s3:*", + ] + + resources = [ + "arn:aws:s3:::${local.opencti_bucket_name}", + "arn:aws:s3:::${local.opencti_bucket_name}/*", + ] + } +} + +resource "aws_iam_policy" "opencti_s3" { + name = "opencti_s3" + policy = data.aws_iam_policy_document.opencti_s3.json +} + +resource "aws_iam_role_policy_attachment" "opencti_s3_attach" { + role = aws_iam_role.opencti_role.name + policy_arn = aws_iam_policy.opencti_s3.arn +} + +# OpenCTI installer script +resource "aws_s3_bucket_object" "opencti-install-script" { + bucket = aws_s3_bucket.opencti_bucket.id + key = "opencti-installer.sh" + source = "../opencti_scripts/installer.sh" +} + +# OpenCTI connectors script +resource "aws_s3_bucket_object" "opencti-connectors-script" { + bucket = aws_s3_bucket.opencti_bucket.id + key = "opencti-connectors.sh" + source = "../opencti_scripts/connectors.sh" +} diff --git a/aws/terraform.tfvars b/aws/terraform.tfvars new file mode 100644 index 0000000..90f2a92 --- /dev/null +++ b/aws/terraform.tfvars @@ -0,0 +1,7 @@ +# allowed_ips_application = ["0.0.0.0/0"] +# availability_zone = "us-east-1a" +# login_email = "login.email@example.com" +# region = "us-east-1" +# root_volume_size = 32 +subnet_id = "" +vpc_id = "" diff --git a/aws/variables.tf b/aws/variables.tf new file mode 100644 index 0000000..351c847 --- /dev/null +++ b/aws/variables.tf @@ -0,0 +1,39 @@ +variable "allowed_ips_application" { + description = "List of IP addresses allowed to access application on port 4000 of public IP. Default is all IPs." + type = list(string) + default = ["0.0.0.0/0"] +} + +variable "availability_zone" { + description = "The availability zone to use." + type = string + default = "us-east-1a" +} + +variable "login_email" { + description = "The e-mail address to use for logging into the OpenCTI instance." + type = string + default = "login.email@example.com" +} + +variable "region" { + description = "The region to deploy in." + type = string + default = "us-east-1" +} + +variable "root_volume_size" { + description = "The size of the root volume." + type = number + default = 32 +} + +variable "subnet_id" { + description = "The subnet ID to use." + type = string +} + +variable "vpc_id" { + description = "The VPC ID to use." + type = string +} diff --git a/iam.tf b/iam.tf deleted file mode 100644 index bbd0d18..0000000 --- a/iam.tf +++ /dev/null @@ -1,40 +0,0 @@ -# IAM initial config -data "aws_iam_policy_document" "opencti-assume-role" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["ec2.amazonaws.com"] - } - } -} - -resource "aws_iam_role" "opencti" { - name = "opencti_role" - assume_role_policy = data.aws_iam_policy_document.opencti-assume-role.json -} - -resource "aws_iam_instance_profile" "opencti-profile" { - name = "opencti_profile" - role = aws_iam_role.opencti.name -} - -# AWS Systems Manager (SSM) -data "aws_iam_policy" "ssm" { - arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" -} - -resource "aws_iam_role_policy_attachment" "opencti-ssm-attach" { - role = aws_iam_role.opencti.name - policy_arn = data.aws_iam_policy.ssm.arn -} - -data "aws_iam_policy" "s3readonly" { - arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" -} - -resource "aws_iam_role_policy_attachment" "opencti-readonly-attach" { - role = aws_iam_role.opencti.name - policy_arn = data.aws_iam_policy.s3readonly.arn -} diff --git a/main.tf b/main.tf deleted file mode 100644 index 273e415..0000000 --- a/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -provider "aws" { - region = "us-east-1" - shared_credentials_file = "/path/to/your/.aws/credentials" - profile = "default" -} - -locals { - # Ubuntu 20.04 LTS - ami_id = "ami-0074ee617a234808d" - - opencti_bucket_name = "opencti-storage" - opencti_install_email = "login.email@example.com" - opencti_install_script_name = "opencti-installer.sh" - opencti_connectors_script_name = "opencti-connectors.sh" - vpc_id = "vpc-FILLTHISIN" - subnet_id = "subnet-FILLTHISIN" - instance_type = "t3.medium" -} diff --git a/opencti_scripts/connectors.sh b/opencti_scripts/connectors.sh index a9fea60..130004c 100644 --- a/opencti_scripts/connectors.sh +++ b/opencti_scripts/connectors.sh @@ -140,8 +140,8 @@ warn_user # This will only set up your instance for the connectors enabled. You must supply an API token (e.g., alienvault token) and enable the service. # It should be safe to run this after changing configs or enabling services. declare -A CONNECTORS; -CONNECTORS['alienvault']=0 # this -CONNECTORS['amitt']=0 # this +CONNECTORS['alienvault']=0 +CONNECTORS['amitt']=0 CONNECTORS['crowdstrike']=0 CONNECTORS['cryptolaemus']=0 CONNECTORS['cve']=1 @@ -173,7 +173,7 @@ done if [[ ! $show_user_prompt ]] then echo - read -p "Are you sure you want to continue with the list above? " -n 1 -r + read -p "Are you sure you want to continue with the list above? [y/N] " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]] then diff --git a/opencti_scripts/installer.sh b/opencti_scripts/installer.sh index 76fac58..bbe8b6b 100644 --- a/opencti_scripts/installer.sh +++ b/opencti_scripts/installer.sh @@ -58,10 +58,12 @@ function print_banner { # Parameters: # - $1: section heading function log_section_heading { + echo echo "###^^^###^^^###^^^###^^^###" date --iso-8601=seconds echo $1 echo "###^^^###^^^###^^^###^^^###" + echo } # Function: check_root @@ -114,11 +116,11 @@ function check_apt_pkg { if [[ $(dpkg -l | grep $1) ]] then echo >&2 "$1 found, attempting upgrade: executing apt-get -y install --only-upgrade '$1''$2'"; - DEBIAN_FRONTEND=noninteractive apt -qq install --only-upgrade "$1""$2" > /dev/null 2>&1; + DEBIAN_FRONTEND=noninteractive apt -qq install --only-upgrade "$1""$2" quit_on_error "Upgrading $1$2" else echo >&2 "$1 missing, attempting install: executing apt-get -y install '$1''$2'"; - DEBIAN_FRONTEND=noninteractive apt -qq -y install "$1""$2" > /dev/null 2>&1; + DEBIAN_FRONTEND=noninteractive apt -qq -y install "$1""$2" quit_on_error "Installing $1$2" fi } @@ -306,6 +308,7 @@ sudo add-apt-repository 'deb [ arch=all ] https://repo.grakn.ai/repository/apt/ update_apt_pkg # apt-get install -y grakn-console=2.0.0-alpha-3 # Required dependency # apt-get install -y grakn-core-all +check_apt_pkg 'grakn-bin' '=2.0.0-alpha-6' check_apt_pkg 'grakn-core-server' "=${grakn_version}" check_apt_pkg 'grakn-console' "=${grakn_version}" check_apt_pkg 'grakn-core-all' "=${grakn_version}" @@ -329,6 +332,21 @@ enable_service 'grakn' ## Elasticsearch log_section_heading "Elasticsearch" +echo "Setting up logrotate for Elasticsearch" +# rotate 20 logs at 50M means a maximum of 1GB Elasticsearch logs. +cat < /etc/logrotate.d/elasticsearch +/var/log/elasticsearch/*.log { + daily + rotate 20 + size 50M + copytruncate + compress + delaycompress + missingok + notifempty + create 644 elasticsearch elasticsearch +} +EOT wget -qO - 'https://artifacts.elastic.co/GPG-KEY-elasticsearch' | apt-key add - add-apt-repository "deb https://artifacts.elastic.co/packages/7.x/apt stable main" update_apt_pkg @@ -463,6 +481,7 @@ update_apt_pkg check_apt_pkg 'rabbitmq-server' "=${rabbitmq_ver}" enable_service 'rabbitmq-server' +# Set RabbitMQ environment variables RRMQUNAME="rabbitadmin" # rabbitmq doesn't like '/' @@ -503,6 +522,7 @@ log_section_heading "OpenCTI package installation" echo "OpenCTI: download tarball" wget --quiet -O opencti-release-${opencti_ver}.tar.gz "https://github.com/OpenCTI-Platform/opencti/releases/download/${opencti_ver}/opencti-release-${opencti_ver}.tar.gz" tar -xzf "opencti-release-${opencti_ver}.tar.gz" --directory "/opt/" +rm "opencti-release-${opencti_ver}.tar.gz" echo "Changing owner of ${opencti_dir} to:" $(whoami)":"$(id -gn) chown -R $(whoami):$(id -gn) "${opencti_dir}" diff --git a/s3.tf b/s3.tf deleted file mode 100644 index acf0f3f..0000000 --- a/s3.tf +++ /dev/null @@ -1,42 +0,0 @@ -# S3 resources -resource "aws_s3_bucket" "opencti" { - bucket = local.opencti_bucket_name - acl = "private" -} - -data "aws_iam_policy_document" "opencti-s3" { - statement { - actions = [ - "s3:*", - ] - - resources = [ - "arn:aws:s3:::${local.opencti_bucket_name}", - "arn:aws:s3:::${local.opencti_bucket_name}/*", - ] - } -} - -resource "aws_iam_policy" "opencti-s3" { - name = "opencti_s3" - policy = data.aws_iam_policy_document.opencti-s3.json -} - -resource "aws_iam_role_policy_attachment" "opencti-s3-attach" { - role = aws_iam_role.opencti.name - policy_arn = aws_iam_policy.opencti-s3.arn -} - -# OpenCTI installer script -resource "aws_s3_bucket_object" "opencti-install-script" { - bucket = aws_s3_bucket.opencti.id - key = "opencti-installer.sh" - source = "opencti_scripts/installer.sh" -} - -# OpenCTI connectors script -resource "aws_s3_bucket_object" "opencti-connectors-script" { - bucket = aws_s3_bucket.opencti.id - key = "opencti-connectors.sh" - source = "opencti_scripts/connectors.sh" -} diff --git a/security_group.tf b/security_group.tf deleted file mode 100644 index 2e69754..0000000 --- a/security_group.tf +++ /dev/null @@ -1,24 +0,0 @@ -# Security group -resource "aws_security_group" "opencti" { - name = "opencti" - vpc_id = local.vpc_id - - ingress { - description = "Allow access from these IPs" - from_port = 4000 - to_port = 4000 - protocol = "tcp" - cidr_blocks = ["put.your.ip.here/32", "another.ip.address.here/32"] - } - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } - - tags = { - Name = "opencti" - } -} diff --git a/userdata/installation-wrapper-script.sh b/userdata/installation-wrapper-script.sh index fa95bc3..cd4fe2b 100644 --- a/userdata/installation-wrapper-script.sh +++ b/userdata/installation-wrapper-script.sh @@ -16,7 +16,7 @@ aws s3 cp s3://${opencti_bucket_name}/${opencti_install_script_name} /opt/${open chmod +x /opt/${opencti_install_script_name} echo "Starting OpenCTI installation script" # Run the install script with the provided e-mail address (from main.tf) -/opt/${opencti_install_script_name} -e "${opencti_install_email}" +/opt/${opencti_install_script_name} -e "${login_email}" echo "OpenCTI installation script complete."