From 79a2289c6e24d3e5d89b2183881212ab6455b60a Mon Sep 17 00:00:00 2001 From: Shahzaib Sheikh Date: Wed, 18 Nov 2020 20:04:06 +0500 Subject: [PATCH 1/5] Adds support when bastion host username and mongodb server ssh user name differs --- README.md | 76 +++++++++++++--------- examples/mongodb-in-private-subnet/main.tf | 1 + main.tf | 5 +- variables.tf | 6 ++ 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 8fe85c3..127a770 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Terraform MongoDB provisioner using AWS EC2 -> This module is part of a project to simplify the provisioning of MongoDB on AWS cloud using Terraform. -You may also wish to consider [one of the other approaches](https://github.com/everest-engineering/terraform-aws-mongodb). +> This module is part of a project to simplify the provisioning of MongoDB on AWS cloud using Terraform. +> You may also wish to consider [one of the other approaches](https://github.com/everest-engineering/terraform-aws-mongodb). This module provision MongoDB server on AWS EC2 instance using Ansible provisioner. @@ -11,18 +11,21 @@ This module uses [undergreen.mongodb](https://galaxy.ansible.com/undergreen/mong So, you can use any of the [platforms supported by **undergreen.mongodb**](https://github.com/UnderGreen/ansible-role-mongodb/blob/master/README.md) role while selecting the AMI ID. ### Pros + 1. Simplified MongoDB provisioner supporting Replication. 2. EC2 instances can be provisioned with newer MongoDB versions and attach to existing EBS data volumes if versions are compatible. 3. MongoDB can be provisioned in either public subnet or in private subnet using Bastion host. ### Cons + 1. Dynamic increase/decrease of number of replica nodes is not yet supported. 2. No out-of-the-box monitoring support. ## Dependencies ### 1. Ansible provisioner -This module depends on the Ansible provisioner. + +This module depends on the Ansible provisioner. See the [installation instructions](https://github.com/radekg/terraform-provisioner-ansible#installation). Download a [Prebuilt release available on GitHub](https://github.com/radekg/terraform-provisioner-ansible/releases), @@ -33,6 +36,7 @@ rename it to **terraform-provisioner-ansible** and place it in **~/.terraform.d/ `> ansible-galaxy install undergreen.mongodb` ### 3. SSH Keys + User needs to provide SSH keys for this module to perform remote provisioning. You can generate SSH keys using the following command: @@ -43,18 +47,19 @@ For more info on generating SSH keys refer https://help.github.com/en/github/aut ## Prerequisite -The data should be persistent across the EC2 restarts/termination. +The data should be persistent across the EC2 restarts/termination. So a better approach would be to store MongoDB data on externally created EBS volume and attach/mount to EC2 instance. > Note: To attach EBS volume to an EC2 instance they both need to be in same availability_zone. ## How to use this module? + We can use this module to provision MongoDB server either in public subnet or in a private subnet. ### 1. Provision MongoDB in Public Subnet If we want to provision MongoDB in a public subnet then MongoDB server can be provisioned using SSH directly -without requiring bastion host as follows: +without requiring bastion host as follows: ```hcl-terraform module "mongodb" { @@ -97,7 +102,8 @@ output "mongo_server_private_ip" { For more details see Example 1 - [mongodb-in-public-subnet](examples/mongodb-in-public-subnet) ### 2. Provision MongoDB in Private Subnet -If we want to provision MongoDB in a private subnet then a Bastion host(a.k.a Jump host) + +If we want to provision MongoDB in a private subnet then a Bastion host(a.k.a Jump host) is required to provision MongoDB using SSH. ```hcl-terraform @@ -116,6 +122,7 @@ module "mongodb" { private_key = file("~/.ssh/id_rsa") public_key = file("~/.ssh/id_rsa.pub") bastion_host = "BASTION_HOST_IP_HERE" + bastion_user = "BASTION_HOST_SSH_USER_HERE" tags = { Name = "MongoDB Server" Environment = "terraform-mongo-testing" @@ -126,32 +133,33 @@ module "mongodb" { For more details see Example 2 - [mongodb-in-private-subnet](examples/mongodb-in-private-subnet) ### Inputs -| Name | Description | Type | Default | Required | -| ----------------- | :-------------------------------- | ------| -------| ---------| -| vpc_id | The VPC ID to launch in | string | n/a | yes -| subnet_id | The VPC Subnet ID to launch in | string | n/a | yes -| data_volumes | The EBS volume ids and their respective availability zones. | `list(object({ ebs_volume_id, availability_zone}))` | n/a | yes -| private_key | Path to private key file | string | n/a | yes -| public_key | Path to public key file | string | n/a | yes -| ssh_user | SSH user name | string | n/a | yes -| bastion_host | Bastion host Public IP | string | n/a | yes -| instance_type | The type of instance to start | string | "t2.micro" | no -| ami | ID of AMI to use for the instance | string | "" | no -| ami_filter_name | AMI selection filter by name. This will be ignored if `ami` value is specified | string | "ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*" | no -| ami_owners | AMI owners filter criteria | list(string) | `["self", "amazon", "aws-marketplace"]` | no -| keypair_name | Keypair name | string | "mongo-publicKey" | no -| mongodb_version | MongoDB version to install | string | "4.2" | no -| replicaset_name | MongoDB replicaset name | string | "" | no -| replica_count | Number of Replica nodes | number | 1 | no -| tags | Tag for EC2 | map(string) | {} | no -### Outputs +| Name | Description | Type | Default | Required | +| --------------- | :----------------------------------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------------- | -------- | +| vpc_id | The VPC ID to launch in | string | n/a | yes | +| subnet_id | The VPC Subnet ID to launch in | string | n/a | yes | +| data_volumes | The EBS volume ids and their respective availability zones. | `list(object({ ebs_volume_id, availability_zone}))` | n/a | yes | +| private_key | Path to private key file | string | n/a | yes | +| public_key | Path to public key file | string | n/a | yes | +| ssh_user | SSH user name | string | n/a | yes | +| bastion_host | Bastion host Public IP | string | n/a | yes | +| bastion_user | Bastion host User name | string | `var.ssh_user` | no | +| instance_type | The type of instance to start | string | "t2.micro" | no | +| ami | ID of AMI to use for the instance | string | "" | no | +| ami_filter_name | AMI selection filter by name. This will be ignored if `ami` value is specified | string | "ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-\*" | no | +| ami_owners | AMI owners filter criteria | list(string) | `["self", "amazon", "aws-marketplace"]` | no | +| keypair_name | Keypair name | string | "mongo-publicKey" | no | +| mongodb_version | MongoDB version to install | string | "4.2" | no | +| replicaset_name | MongoDB replicaset name | string | "" | no | +| replica_count | Number of Replica nodes | number | 1 | no | +| tags | Tag for EC2 | map(string) | {} | no | -| Name | Description | -| ------ | ----------| -| mongo_server_public_ip | Public IP of provisioned MongoDB server | -| mongo_server_private_ip | Private IP of provisioned MongoDB server | +### Outputs +| Name | Description | +| ----------------------- | ---------------------------------------- | +| mongo_server_public_ip | Public IP of provisioned MongoDB server | +| mongo_server_private_ip | Private IP of provisioned MongoDB server | ## Testing @@ -162,17 +170,21 @@ For more details see Example 2 - [mongodb-in-private-subnet](examples/mongodb-in > cd test > go test -v ``` + ## Contributing + We appreciate your help! - -[Open an issue](https://github.com/everest-engineering/terraform-aws-mongodb-ec2/issues/new/choose) or submit a pull request for an enhancement. -Browse through the + +[Open an issue](https://github.com/everest-engineering/terraform-aws-mongodb-ec2/issues/new/choose) or submit a pull request for an enhancement. +Browse through the [current open issues](https://github.com/everest-engineering/terraform-aws-mongodb-ec2/issues). ## License + [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ## Authors + [![EverestEngineering](https://github.com/everest-engineering/terraform-aws-mongodb-ec2/blob/master/images/banner.png?raw=true)](https://everest.engineering) [![License: EverestEngineering](https://img.shields.io/badge/Copyright%20%C2%A9-EVERESTENGINEERING-blue)](https://everest.engineering) diff --git a/examples/mongodb-in-private-subnet/main.tf b/examples/mongodb-in-private-subnet/main.tf index d435e18..75d78a0 100644 --- a/examples/mongodb-in-private-subnet/main.tf +++ b/examples/mongodb-in-private-subnet/main.tf @@ -18,6 +18,7 @@ module "mongodb" { private_key = file("~/.ssh/id_rsa") public_key = file("~/.ssh/id_rsa.pub") bastion_host = var.bastion_host + bastion_user = "ubuntu" tags = { Name = "MongoDB Server" Environment = "terraform-mongo-testing" diff --git a/main.tf b/main.tf index feb24a8..43498a7 100644 --- a/main.tf +++ b/main.tf @@ -32,6 +32,7 @@ resource "aws_instance" "mongo_server" { user = var.ssh_user private_key = var.private_key bastion_host = var.bastion_host + bastion_user = var.bastion_user == "" ? var.ssh_user : var.bastion_user agent = true } @@ -63,6 +64,7 @@ resource "aws_volume_attachment" "mongo-data-vol-attachment" { user = var.ssh_user private_key = var.private_key bastion_host = var.bastion_host + bastion_user = var.bastion_user == "" ? var.ssh_user : var.bastion_user agent = true } @@ -115,6 +117,7 @@ resource "null_resource" "replicaset_initialization" { user = var.ssh_user private_key = var.private_key bastion_host = var.bastion_host + bastion_user = var.bastion_user == "" ? var.ssh_user : var.bastion_user agent = true } -} \ No newline at end of file +} diff --git a/variables.tf b/variables.tf index d09a0a3..f2173d6 100644 --- a/variables.tf +++ b/variables.tf @@ -79,6 +79,12 @@ variable "ssh_user" { description = "SSH user name" } +variable "bastion_user" { + type = string + description = "bastion SSH user name" + default = "" +} + variable "replicaset_name" { type = string description = "MongoDB ReplicaSet Name" From 9ecc24be8f36f0bf4a11cc4570244ee6c849f3c9 Mon Sep 17 00:00:00 2001 From: Shahzaib Sheikh Date: Thu, 19 Nov 2020 02:32:02 +0500 Subject: [PATCH 2/5] Uses private ip for replication configuration when deploying in private subnet. Previously it was causing replication to fail because public ip was being used to replication configuration. --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 43498a7..d14753d 100644 --- a/main.tf +++ b/main.tf @@ -100,7 +100,7 @@ resource "null_resource" "replicaset_initialization" { provisioner "file" { content = templatefile("${path.module}/provisioning/init-replicaset.js.tmpl", { replicaSetName = var.replicaset_name - ip_addrs = aws_instance.mongo_server.*.public_ip + ip_addrs = var.bastion_host == "" ? aws_instance.mongo_server.*.public_ip : aws_instance.mongo_server.*.private_ip }) destination = "/tmp/init-replicaset.js" } From c3f6aa7b0a85e56bf3aa301791fe5a8dfe075a04 Mon Sep 17 00:00:00 2001 From: Shahzaib Sheikh Date: Thu, 19 Nov 2020 02:47:35 +0500 Subject: [PATCH 3/5] Uses private ip for replication configuration when deploying in private subnet. Previously it was causing replication to fail because public ip was being used to replication configuration. --- main.tf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index feb24a8..1e08906 100644 --- a/main.tf +++ b/main.tf @@ -98,7 +98,8 @@ resource "null_resource" "replicaset_initialization" { provisioner "file" { content = templatefile("${path.module}/provisioning/init-replicaset.js.tmpl", { replicaSetName = var.replicaset_name - ip_addrs = aws_instance.mongo_server.*.public_ip + ip_addrs = var.bastion_host == "" ? aws_instance.mongo_server.*.public_ip : aws_instance.mongo_server.*.private_ip + }) destination = "/tmp/init-replicaset.js" } @@ -117,4 +118,4 @@ resource "null_resource" "replicaset_initialization" { bastion_host = var.bastion_host agent = true } -} \ No newline at end of file +} From d12d479e0a58adf7b60e7437c5f5ec605a1b8ece Mon Sep 17 00:00:00 2001 From: Shahzaib Sheikh Date: Thu, 19 Nov 2020 02:50:52 +0500 Subject: [PATCH 4/5] Avoids associating public ip address for server deployed in private subnets --- main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index feb24a8..d00041f 100644 --- a/main.tf +++ b/main.tf @@ -23,7 +23,7 @@ resource "aws_instance" "mongo_server" { vpc_security_group_ids = [aws_security_group.sg_mongodb.id] key_name = aws_key_pair.mongo_keypair.key_name availability_zone = var.data_volumes[count.index].availability_zone - associate_public_ip_address = true + associate_public_ip_address = var.bastion_host == "" ? true : false tags = var.tags connection { @@ -117,4 +117,4 @@ resource "null_resource" "replicaset_initialization" { bastion_host = var.bastion_host agent = true } -} \ No newline at end of file +} From 30eb41cde62aa72549932e2dff3a417ac816bb0e Mon Sep 17 00:00:00 2001 From: Shahzaib Sheikh Date: Fri, 20 Nov 2020 20:57:03 +0500 Subject: [PATCH 5/5] Add configuration parameters in module --- main.tf | 12 ++++++++++-- variables.tf | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index a39d947..d2cf653 100644 --- a/main.tf +++ b/main.tf @@ -86,8 +86,16 @@ resource "aws_volume_attachment" "mongo-data-vol-attachment" { file_path = "${path.module}/provisioning/playbook.yaml" } extra_vars = { - mongodb_version = var.mongodb_version - mongodb_replication_replset = var.replicaset_name + mongodb_version = var.mongodb_version + mongodb_replication_replset = var.replicaset_name + mongodb_keyfile_content = file(var.keyfile) + mongodb_security_authorization = var.security_authorization + mongodb_user_admin_name = var.admin_user_name + mongodb_user_admin_password = var.admin_user_password + mongodb_root_admin_name = var.root_user_name + mongodb_root_admin_password = var.root_user_password + mongodb_root_backup_name = var.backup_user_name + mongodb_root_backup_password = var.backup_user_password } groups = local.ansible_host_group } diff --git a/variables.tf b/variables.tf index f2173d6..952834b 100644 --- a/variables.tf +++ b/variables.tf @@ -96,3 +96,43 @@ variable "replica_count" { description = "Number of Replica nodes" default = 1 } +variable "security_authorization" { + type = string + description = "Authorization" + default = "disabled" +} +variable "admin_user_name" { + type = string + description = "Admin user name" + default = "admin" +} +variable "admin_user_password" { + type = string + description = "Admin user password" + default = "passw0rd" +} +variable "root_user_name" { + type = string + description = "Root user name" + default = "root" +} +variable "root_user_password" { + type = string + description = "Root user password" + default = "passw0rd" +} +variable "backup_user_name" { + type = string + description = "Backup user name" + default = "root" +} +variable "backup_user_password" { + type = string + description = "Backup user password" + default = "passw0rd" +} +variable "keyfile" { + type = string + description = "keyfile path" + default = "./keyfile" +}