Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support when bastion host username and mongodb server ssh user name is different #5

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
76 changes: 44 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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),
Expand All @@ -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:
Expand All @@ -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" {
Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand All @@ -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

Expand All @@ -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)
1 change: 1 addition & 0 deletions examples/mongodb-in-private-subnet/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
21 changes: 16 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}

Expand All @@ -84,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
}
Expand All @@ -98,7 +108,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"
}
Expand All @@ -115,6 +125,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
}
}
}
46 changes: 46 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -90,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"
}