diff --git a/README.md b/README.md index 0f5e7d8..71e99db 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,9 @@ Here are some resources to get you started! If you find any challenges from this module "rubrik_aws_cloud_cluster" { source = "rubrikinc/rubrik-cloud-cluster/aws" - aws_vpc_security_group_ids = ["sg-0fc82928bd323ed3qq"] - aws_subnet_id = "subnet-0278a40b29e52203a" + aws_region = "us-west-1" + aws_subnet_id = "subnet-1234567890abcdefg" + aws_ami_filter = ["rubrik-mp-cc-7*"] cluster_name = "rubrik-cloud-cluster" admin_email = "build@rubrik.com" dns_search_domain = ["rubrikdemo.com"] @@ -30,34 +31,94 @@ module "rubrik_aws_cloud_cluster" { The following are the variables accepted by the module. +#### Instance/Node Settings + | Name | Description | Type | Default | Required | | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | | aws_region | The region to deploy Rubrik Cloud Cluster nodes. | string | | yes | -| aws_instance_type | The type of instance to use as Rubrik Cloud Cluster nodes. | string | m5.xlarge | no | -| aws_disable_api_termination | If true, enables EC2 Instance Termination Protection | bool | true | no | -| aws_vpc_security_group_name_cloud_cluster_nodes | The name of the security group to create for Rubrik Cloud Cluster to use. | string | Rubrik Cloud Cluster | yes | -| aws_vpc_security_group_name_cloud_cluster_hosts | The name of the security group to create for Rubrik Cloud Cluster to communicate with EC2 instances. | string | Rubrik Cloud Cluster Hosts | yes | +| aws_instance_type | The type of instance to use as Rubrik Cloud Cluster nodes. CC-ES requires m5.4xlarge. | string | m5.4xlarge | no | +| aws_disable_api_termination | If true, enables EC2 Instance Termination Protection on the Rubrik Cloud Cluster nodes. | bool | true | no | +| aws_tags | Tags to add to the resources that this Terraform script creates, including the Rubrik cluster nodes. | map | | no | +| number_of_nodes | The total number of nodes in Rubrik Cloud Cluster. | int | 3 | no | +| aws_ami_owners | AWS marketplace account(s) that owns the Rubrik Cloud Cluster AMIs. | list | ["679593333241"] | no | +| aws_ami_filter | Cloud Cluster AWS AMI name pattern(s) to search for. Use [\"rubrik-mp-cc-*\"]. Where is the major version of CDM. | list | | yes | +| aws_image_id | AWS Image ID to deploy. Set to 'latest' or leave blank to deploy the latest version as determined by `aws_ami_filter`. | string | latest | no | +| create_key_pair | If true, a new AWS SSH Key-Pair will be created using the aws_key_pair_name and aws_public_key settings. | bool | true | no | +| aws_key_pair_name | Name for the AWS SSH Key-Pair being created or the existing AWS SSH Key-Pair being used. | string | | no | +| aws_public_key | The public key material needed to create an AWS Key-Pair for use with Rubrik Cloud Cluster. | string | | no | +| private-key-file | If a new AWS SSH Key-Pair is generated, the name of the file to save the private key material in. | string | ./.terraform/cc-key.pem | no | + +*Note: When using the `aws_tags` variable, the "Name" tag is automatically used by this TF for those resources that support it.* + +*Note: The `aws_ami_filter` and `aws_ami_owners` variables are only used when the `aws_image_id` variable is blank or set to `latest`* + +*Note: When using the `aws_image_id` variable, see [Selecting a specific image](#selecting-a-specific-image) for details on finding images.* + +*Note: When using the `aws_key_pair_name` variable, if a new AWS SSH Key-Pair is being created and no name is specified, a name will be automatically generated.* + +*Note: When using the `aws_public_key` variable, if a new AWS SSH Key-Pair is being created and no material is provided, new key material will be auto generated.* + +
+ +#### Network Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| create_cloud_cluster_nodes_sg | If true, creates a new Security Group for node to node traffic within the Rubrik cluster. | bool | true | no | +| aws_vpc_cloud_cluster_nodes_sg_name | The name of the security group to create for Rubrik Cloud Cluster to use. | string | Rubrik Cloud Cluster | no | +| cloud_cluster_nodes_admin_cidr | The CIDR range for the systems used to administer the Cloud Cluster via SSH and HTTPS. | string | 0.0.0.0/0 | no | +| create_cloud_cluster_hosts_sg | If true, creates a new Security Group for node to host traffic from the Rubrik cluster. | string | true | no | +| aws_vpc_cloud_cluster_hosts_sg_name | The name of the security group to create for Rubrik Cloud Cluster to communicate with EC2 instances. | string | Rubrik Cloud Cluster Hosts | no | +| aws_cloud_cluster_nodes_sg_ids | Additional security groups to add to Rubrik cluster nodes. | string | | no | | aws_subnet_id | The VPC Subnet ID to launch Rubrik Cloud Cluster in. | string | | yes | -| aws_public_key | he public key material needed to create an AWS key pair for use with Rubrik Cloud Cluster. | string | | yes | -| number_of_nodes | The total number of nodes in Rubrik Cloud Cluster. | int | 4 | no | -| cluster_disk_type | The disk type to use for Rubrik Cloud Cluster data disks (sc1 or st1). NOTE: st1 disks require six 8TB disks. | string | st1 | yes | -| cluster_disk_size | The size of each the three data disks in each node. | string | 1024 | no | + +#### Storage Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| cluster_disk_type | Disk type for the data disks (st1, sc1 or gp2). Use gp2 for CC-ES. Use sc1 for 48TB CC nodes. Use st1 for all others. | string | gp2 | no | +| cluster_disk_size | The size (in GB) of each data disk on each node. Cloud Cluster ES only requires 1 512 GB disk per node. | string | 512 | no | +| cluster_disk_count | The number of disks for each node in the cluster. Set to 1 to use with S3 storage for Cloud Cluster ES. | int | 1 | no | + +#### Cloud Cluster ES Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| create_iam_role | If true, create required IAM role, role policy, and instance profile needed for Cloud Cluster ES. | bool | true | no | +| aws_cloud_cluster_iam_role_name | AWS IAM Role name for Cloud Cluster ES. If blank a name will be auto generated. Required if create_iam_role is false. | string | | no | +| aws_cloud_cluster_iam_role_policy_name | AWS IAM Role policy name for Cloud Cluster ES if create_iam_role is true. If blank a name will be auto generated. | string | | no | +| aws_cloud_cluster_ec2_instance_profile_name | AWS EC2 Instance Profile name that links the IAM Role to Cloud Cluster ES. If blank a name will be auto generated. | string | | no | +| create_s3_bucket | If true, create am S3 bucket for Cloud Cluster ES data storage. | bool | true | no | +| s3_bucket_name | Name of the S3 bucket to use with Cloud Cluster ES data storage. If blank a name will be auto generated. | string | | no | +| create_s3_vpc_endpoint | If true, create a VPC Endpoint and S3 Endpoint Service for Cloud Cluster ES. | bool | true | no | + +#### Bootstrap Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | | cluster_name | Unique name to assign to Rubrik Cloud Cluster. Also used for EC2 instance name tag. For example, rubrik-1, rubrik-2 etc. | string | | yes | | admin_email | The Rubrik Cloud Cluster sends messages for the admin account to this email address. | string | | yes | | admin_password | Password for the Rubrik Cloud Cluster admin account. | string | RubrikGoForward | no | | dns_search_domain | List of search domains that the DNS Service will use to resolve hostnames that are not fully qualified. | list | | yes | -| dns_name_servers | List of the IPv4 addresses of the DNS servers. | list | | yes | -| ntp_servers | List of FQDN or IPv4 addresses of a network time protocol (NTP) server(s) | list | ["8.8.8.8"] | no | +| dns_name_servers | List of the IPv4 addresses of the DNS servers. | list | ["169.254.169.253"] | no | +| ntp_servers | List of FQDN or IPv4 addresses of a network time protocol (NTP) server(s) | list | ["169.254.169.123"] | no | | timeout | The number of seconds to wait to establish a connection the Rubrik cluster before returning a timeout error. | int | 15 | no | ## Prerequisites There are a few services you'll need in order to get this project off the ground: -- [Terraform](https://www.terraform.io/downloads.html) v0.15.4 or greater +- [Terraform](https://www.terraform.io/downloads.html) v1.2.2 or greater - [Rubrik Provider for Terraform](https://github.com/rubrikinc/rubrik-provider-for-terraform) - provides Terraform functions for Rubrik - Only required to run the sample Rubrik Bootstrap command +- The Rubik Cloud Cluster product in the AWS Marketplace must be subscribed to. Otherwise an error like this will be displayed: + > Error: creating EC2 Instance: OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. To do so please visit https://aws.amazon.com/marketplace/pp?sku= + + If this occurs, open the specific link from the error, while logged into the AWS account where Cloud Cluster will be deployed. Follow the instructions for subscribing to the product. + +## Changes +Several variables have changed with this iteration of the script. Upgrades to existing deployments may cause unwanted changes. Be sure to check the changes of `terraform plan` before `terraform apply` to avoid disruptive behavior. ## How You Can Help We glady welcome contributions from the community. From updating the documentation to adding more functionality, all ideas are welcome. Thank you in advance for all of your issues, pull requests, and comments! diff --git a/docs/quick-start.md b/docs/quick-start.md index a122ac7..58f75c1 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -10,8 +10,9 @@ In your [Terraform configuration](https://learn.hashicorp.com/terraform/getting- module "rubrik_aws_cloud_cluster" { source = "rubrikinc/rubrik-cloud-cluster/aws" - aws_vpc_security_group_ids = ["sg-0fc82928bd323ed3qq"] - aws_subnet_id = "subnet-0278a40b29e52203a" + aws_region = "us-west-1" + aws_subnet_id = "subnet-1234567890abcdefg" + aws_ami_filter = ["rubrik-mp-cc-7*"] cluster_name = "rubrik-cloud-cluster" admin_email = "build@rubrik.com" dns_search_domain = ["rubrikdemo.com"] @@ -25,24 +26,77 @@ You may also add additional variables, such as `ntp_servers`, to overwrite the d The following are the variables accepted by the module. +### Instance/Node Settings + | Name | Description | Type | Default | Required | | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | | aws_region | The region to deploy Rubrik Cloud Cluster nodes. | string | | yes | -| aws_instance_type | The type of instance to use as Rubrik Cloud Cluster nodes. | string | m5.xlarge | no | -| aws_disable_api_termination | If true, enables EC2 Instance Termination Protection | bool | true | no | -| aws_vpc_security_group_name_cloud_cluster_nodes | The name of the security group to create for Rubrik Cloud Cluster to use. | string | Rubrik Cloud Cluster | yes | -| aws_vpc_security_group_name_cloud_cluster_hosts | The name of the security group to create for Rubrik Cloud Cluster to communicate with EC2 instances. | string | Rubrik Cloud Cluster Hosts | yes | +| aws_instance_type | The type of instance to use as Rubrik Cloud Cluster nodes. CC-ES requires m5.4xlarge. | string | m5.4xlarge | no | +| aws_disable_api_termination | If true, enables EC2 Instance Termination Protection on the Rubrik Cloud Cluster nodes. | bool | true | no | +| aws_tags | Tags to add to the resources that this Terraform script creates, including the Rubrik cluster nodes. | map | | no | +| number_of_nodes | The total number of nodes in Rubrik Cloud Cluster. | int | 3 | no | +| aws_ami_owners | AWS marketplace account(s) that owns the Rubrik Cloud Cluster AMIs. Use [\"345084742485\"] for AWS GovCloud. | list | ["679593333241"] | no | +| aws_ami_filter | Cloud Cluster AWS AMI name pattern(s) to search for. Use [\"rubrik-mp-cc-*\"]. Where is the major version of CDM. | list | | yes | +| aws_image_id | AWS Image ID to deploy. Set to 'latest' or leave blank to deploy the latest version as determined by `aws_ami_filter`. | string | latest | no | +| create_key_pair | If true, a new AWS SSH Key-Pair will be created using the aws_key_pair_name and aws_public_key settings. | bool | true | no | +| aws_key_pair_name | Name for the AWS SSH Key-Pair being created or the existing AWS SSH Key-Pair being used. | string | | no | +| aws_public_key | The public key material needed to create an AWS Key-Pair for use with Rubrik Cloud Cluster. | string | | no | +| private-key-file | If a new AWS SSH Key-Pair is generated, the name of the file to save the private key material in. | string | ./.terraform/cc-key.pem | no | + +*Note: When using the `aws_tags` variable, the "Name" tag is automatically used by this TF for those resources that support it.* + +*Note: The `aws_ami_filter` and `aws_ami_owners` variables are only used when the `aws_image_id` variable is blank or set to `latest`* + +*Note: When using the `aws_image_id` variable, see [Selecting a specific image](#selecting-a-specific-image) for details on finding images.* + +*Note: When using the `aws_key_pair_name` variable, if a new AWS SSH Key-Pair is being created and no name is specified, a name will be automatically generated.* + +*Note: When using the `aws_public_key` variable, if a new AWS SSH Key-Pair is being created and no material is provided, new key material will be auto generated.* + +
+ +### Network Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| create_cloud_cluster_nodes_sg | If true, creates a new Security Group for node to node traffic within the Rubrik cluster. | bool | true | no | +| aws_vpc_cloud_cluster_nodes_sg_name | The name of the security group to create for Rubrik Cloud Cluster to use. | string | Rubrik Cloud Cluster | no | +| cloud_cluster_nodes_admin_cidr | The CIDR range for the systems used to administer the Cloud Cluster via SSH and HTTPS. | string | 0.0.0.0/0 | no | +| create_cloud_cluster_hosts_sg | If true, creates a new Security Group for node to host traffic from the Rubrik cluster. | string | true | no | +| aws_vpc_cloud_cluster_hosts_sg_name | The name of the security group to create for Rubrik Cloud Cluster to communicate with EC2 instances. | string | Rubrik Cloud Cluster Hosts | no | +| aws_cloud_cluster_nodes_sg_ids | Additional security groups to add to Rubrik cluster nodes. | string | | no | | aws_subnet_id | The VPC Subnet ID to launch Rubrik Cloud Cluster in. | string | | yes | -| aws_public_key | he public key material needed to create an AWS key pair for use with Rubrik Cloud Cluster. | string | | yes | -| number_of_nodes | The total number of nodes in Rubrik Cloud Cluster. | int | 4 | no | -| cluster_disk_type | The disk type to use for Rubrik Cloud Cluster data disks (sc1 or st1). NOTE: st1 disks require six 8TB disks. | string | st1 | yes | -| cluster_disk_size | The size of each the three data disks in each node. | string | 1024 | no | + +### Storage Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| cluster_disk_type | Disk type for the data disks (st1, sc1 or gp2). Use gp2 for CC-ES. Use sc1 for 48TB CC nodes. Use st1 for all others. | string | gp2 | no | +| cluster_disk_size | The size (in GB) of each data disk on each node. Cloud Cluster ES only requires 1 512 GB disk per node. | string | 512 | no | +| cluster_disk_count | The number of disks for each node in the cluster. Set to 1 to use with S3 storage for Cloud Cluster ES. | int | 1 | no | + +### Cloud Cluster ES Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | +| create_iam_role | If true, create required IAM role, role policy, and instance profile needed for Cloud Cluster ES. | bool | true | no | +| aws_cloud_cluster_iam_role_name | AWS IAM Role name for Cloud Cluster ES. If blank a name will be auto generated. Required if create_iam_role is false. | string | | no | +| aws_cloud_cluster_iam_role_policy_name | AWS IAM Role policy name for Cloud Cluster ES if create_iam_role is true. If blank a name will be auto generated. | string | | no | +| aws_cloud_cluster_ec2_instance_profile_name | AWS EC2 Instance Profile name that links the IAM Role to Cloud Cluster ES. If blank a name will be auto generated. | string | | no | +| create_s3_bucket | If true, create am S3 bucket for Cloud Cluster ES data storage. | bool | true | no | +| s3_bucket_name | Name of the S3 bucket to use with Cloud Cluster ES data storage. If blank a name will be auto generated. | string | | no | +| create_s3_vpc_endpoint | If true, create a VPC Endpoint and S3 Endpoint Service for Cloud Cluster ES. | bool | true | no | + +### Bootstrap Settings + +| Name | Description | Type | Default | Required | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | :----: | :------------------------: | :------: | | cluster_name | Unique name to assign to Rubrik Cloud Cluster. Also used for EC2 instance name tag. For example, rubrik-1, rubrik-2 etc. | string | | yes | | admin_email | The Rubrik Cloud Cluster sends messages for the admin account to this email address. | string | | yes | | admin_password | Password for the Rubrik Cloud Cluster admin account. | string | RubrikGoForward | no | | dns_search_domain | List of search domains that the DNS Service will use to resolve hostnames that are not fully qualified. | list | | yes | -| dns_name_servers | List of the IPv4 addresses of the DNS servers. | list | | yes | -| ntp_servers | List of FQDN or IPv4 addresses of a network time protocol (NTP) server(s) | list | ["8.8.8.8"] | no | +| dns_name_servers | List of the IPv4 addresses of the DNS servers. | list | ["169.254.169.253"] | no | +| ntp_servers | List of FQDN or IPv4 addresses of a network time protocol (NTP) server(s) | list | ["169.254.169.123"] | no | | timeout | The number of seconds to wait to establish a connection the Rubrik cluster before returning a timeout error. | int | 15 | no | ## Running the Terraform Configuration @@ -51,34 +105,56 @@ This section outlines what is required to run the configuration defined above. ### Prerequisites -- [Terraform](https://www.terraform.io/downloads.html) v0.15.4 or greater +- [Terraform](https://www.terraform.io/downloads.html) v1.2.2 or greater - [Rubrik Provider for Terraform](https://github.com/rubrikinc/rubrik-provider-for-terraform) - provides Terraform functions for Rubrik - Only required to run the sample Rubrik Bootstrap command +- The Rubik Cloud Cluster product in the AWS Marketplace must be subscribed to. Otherwise an error like this will be displayed: + > Error: creating EC2 Instance: OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. To do so please visit https://aws.amazon.com/marketplace/pp?sku= + + If this occurs, open the specific link from the error, while logged into the AWS account where Cloud Cluster will be deployed. Follow the instructions for subscribing to the product. ### Initialize the Directory The directory can be initialized for Terraform use by running the `terraform init` command: ```none +-> terraform init Initializing modules... -- module.rubrik_aws_cloud_cluster - Getting source "rubrikinc/aws-rubrik-cloud-cluster/module" +Downloading registry.terraform.io/terraform-aws-modules/key-pair/aws 1.0.1 for aws_key_pair... +- aws_key_pair in .terraform/modules/aws_key_pair +- cluster_nodes in modules/rubrik_aws_instances +- iam_role in modules/iam_role +Downloading registry.terraform.io/terraform-aws-modules/security-group/aws 4.9.0 for rubrik_hosts_sg... +- rubrik_hosts_sg in .terraform/modules/rubrik_hosts_sg +- rubrik_hosts_sg_rules in modules/rubrik_hosts_sg +Downloading registry.terraform.io/terraform-aws-modules/security-group/aws 4.9.0 for rubrik_hosts_sg_rules.this... +- rubrik_hosts_sg_rules.this in .terraform/modules/rubrik_hosts_sg_rules.this +Downloading registry.terraform.io/terraform-aws-modules/security-group/aws 4.9.0 for rubrik_nodes_sg... +- rubrik_nodes_sg in .terraform/modules/rubrik_nodes_sg +- rubrik_nodes_sg_rules in modules/rubrik_nodes_sg +Downloading registry.terraform.io/terraform-aws-modules/security-group/aws 4.9.0 for rubrik_nodes_sg_rules.this... +- rubrik_nodes_sg_rules.this in .terraform/modules/rubrik_nodes_sg_rules.this +Downloading registry.terraform.io/terraform-aws-modules/s3-bucket/aws 3.2.3 for s3_bucket... +- s3_bucket in .terraform/modules/s3_bucket +- s3_vpc_endpoint in modules/s3_vpc_endpoint +Downloading registry.terraform.io/terraform-aws-modules/vpc/aws 3.14.0 for s3_vpc_endpoint.endpoints... +- s3_vpc_endpoint.endpoints in .terraform/modules/s3_vpc_endpoint.endpoints/modules/vpc-endpoints + +Initializing the backend... Initializing provider plugins... -- Checking for available provider plugins on https://releases.hashicorp.com... -- Downloading plugin for provider "aws" (2.2.0)... -- Downloading plugin for provider "null" (2.1.0)... - -The following providers do not have any version constraints in configuration, -so the latest version was installed. - -To prevent automatic upgrades to new major versions that may contain breaking -changes, it is recommended to add version = "..." constraints to the -corresponding provider blocks in configuration, with the constraint strings -suggested below. - -* provider.aws: version = "~> 2.2" -* provider.null: version = "~> 2.1" +- Reusing previous version of hashicorp/tls from the dependency lock file +- Reusing previous version of hashicorp/local from the dependency lock file +- Reusing previous version of hashicorp/template from the dependency lock file +- Reusing previous version of hashicorp/aws from the dependency lock file +- Installing hashicorp/tls v3.4.0... +- Installed hashicorp/tls v3.4.0 (signed by HashiCorp) +- Installing hashicorp/local v2.2.3... +- Installed hashicorp/local v2.2.3 (signed by HashiCorp) +- Installing hashicorp/template v2.2.0... +- Installed hashicorp/template v2.2.0 (signed by HashiCorp) +- Installing hashicorp/aws v4.15.1... +- Installed hashicorp/aws v4.15.1 (signed by HashiCorp) Terraform has been successfully initialized! @@ -93,7 +169,7 @@ commands will detect it and remind you to do so if necessary. ### Gain Access to the Rubrik Cloud Cluster AMI -The Terraform script will automatically install the latest version of Rubrik Cloud Cluster from the AWS Marketplace. If a different version of Cloud Cluster is required modify the filters in the `data "aws_ami_ids" "rubrik_cloud_cluster"` section of the Terraform script. +The Terraform script will automatically install the latest maintenance release of Rubrik Cloud Cluster major version (as defined by the `aws_ami_filter` variable) from the AWS Marketplace. If a different version of Cloud Cluster is required modify the filters in the `aws_image_id`, `aws_ami_owners` and/or `aws_ami_filter` variables. ### Planning @@ -111,3 +187,86 @@ The Cloud Cluster can now be configured through the Web UI; access to the interf ### Destroying Once the Cloud Cluster is no longer required, it can be destroyed using the `terraform destroy` command, and entering `yes` when prompted. This will also destroy the attached EBS volumes. + +## Selecting a specific image + +To select a specific image to deploy replace the `aws_image_id` variable with the AMI ID of the Rubrik Marketplace Image to deploy. To find a list of the Rubrik Cloud Cluster images that are available in a specific region run the following `aws` cli command (requires that the AWS CLI be installed): + +```none + aws ec2 describe-images \ + --filters 'Name=owner-id,Values=679593333241' 'Name=name,Values=rubrik-mp-cc-*' \ + --query 'sort_by(Images, &CreationDate)[*].{"Create Date":CreationDate, "Image ID":ImageId, Version:Description}' \ + --region '' \ + --output table +``` + +Where is the major version of Rubrik CDM (ex. `rubrik-mp-cc-7*`) + +Example: + +```none +aws ec2 describe-images \ + --filters 'Name=owner-id,Values=679593333241' 'Name=name,Values=rubrik-mp-cc-7*' \ + --query 'sort_by(Images, &CreationDate)[*].{"Create Date":CreationDate, "Image ID":ImageId, Version:Description}' \ + --region 'us-west-2' \ + --output table + +------------------------------------------------------------------------------------------ +| DescribeImages | ++--------------------------+-------------------------+-----------------------------------+ +| Create Date | Image ID | Version | ++--------------------------+-------------------------+-----------------------------------+ +| 2022-02-04T21:49:48.000Z| ami-0056ddcc69df6fb5c | Rubrik OS rubrik-7-0-0-14764 | +| 2022-04-01T00:13:58.000Z| ami-026233b876a279622 | Rubrik OS rubrik-7-0-1-15183 | +| 2022-04-12T04:50:31.000Z| ami-03d68b150241012ec | Rubrik OS rubrik-7-0-1-p1-15197 | +| 2022-04-27T05:56:27.000Z| ami-09a3baba1545aa5f7 | Rubrik OS rubrik-7-0-1-p2-15336 | +| 2022-05-13T21:51:54.000Z| ami-0af1ff3ee7517fefa | Rubrik OS rubrik-7-0-1-p3-15425 | +| 2022-05-20T00:01:55.000Z| ami-0cc1db55e45f3109b | Rubrik OS rubrik-7-0-1-p4-15453 | +| 2022-05-26T19:08:31.000Z| ami-04d6af7c6f6629ce1 | Rubrik OS rubrik-7-0-2-15510 | ++--------------------------+-------------------------+-----------------------------------+ +``` +For AWS Gov cloud change the `owner-id` to `345084742485`. + +Example: + +```none +aws ec2 describe-images \ + --filters 'Name=owner-id,Values=345084742485' 'Name=name,Values=rubrik-mp-cc-7*' \ + --query 'sort_by(Images, &CreationDate)[*].{"Create Date":CreationDate, "Image ID":ImageId, Version:Description}' \ + --region 'us-gov-west-1' \ + --output table + +------------------------------------------------------------------------------------------ +| DescribeImages | ++--------------------------+-------------------------+-----------------------------------+ +| Create Date | Image ID | Version | ++--------------------------+-------------------------+-----------------------------------+ +| 2022-01-27T09:17:44.000Z| ami-038cb33e356dfdb84 | Rubrik OS rubrik-7-0-0-14706 | +| 2022-02-05T20:14:25.000Z| ami-09c62e5a399fc5526 | Rubrik OS rubrik-7-0-0-14764 | +| 2022-04-01T22:44:52.000Z| ami-0852636d1bb4376a9 | Rubrik OS rubrik-7-0-1-15183 | +| 2022-04-13T03:06:33.000Z| ami-0e77ba2b8cdeb645c | Rubrik OS rubrik-7-0-1-p1-15197 | +| 2022-04-28T04:54:07.000Z| ami-0486bfdcbf4ee6d5e | Rubrik OS rubrik-7-0-1-p2-15336 | +| 2022-05-14T19:53:12.000Z| ami-0b519a90ae467950d | Rubrik OS rubrik-7-0-1-p3-15425 | +| 2022-05-20T23:18:12.000Z| ami-060706f9a9462b5e7 | Rubrik OS rubrik-7-0-1-p4-15453 | ++--------------------------+-------------------------+-----------------------------------+ +``` + +## Known issues + +There are a few known issues when using this Terraform module. These are described below. + +### Cloud Cluster ES now the default configuration + +With the 1.0 release of this Terraform module, Cloud Cluster ES is now the default configuration. As a result care should be taken to set the correct variables if classic Cloud Cluster is desired. + + ### Deploying Cloud Cluster from the AWS Marketplace requires subscription + +The Rubik product in the AWS Marketplace must be subscribed to. Otherwise an error like this will be displayed: +> Error: creating EC2 Instance: OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. To do so please visit https://aws.amazon.com/marketplace/pp?sku= + +If this occurs, open the specific link from the error, while logged into the AWS account where Cloud Cluster will be deployed. Follow the instructions for subscribing to the product. +For AWS GovCloud the link points to the public marketplace. Instead of following the link, launch one instance of the major version of Rubrik from the AWS console. This will accept the terms and subscribe to the subscription. Remove the manually launched instance and then run the Terraform again. + +### Variable name changes + +Several variables have changed with this iteration of the script. Upgrades to existing deployments may cause unwanted changes. Be sure to check the changes of `terraform plan` before `terraform apply` to avoid disruptive behavior. \ No newline at end of file diff --git a/main.tf b/main.tf index 2861eb2..d804391 100644 --- a/main.tf +++ b/main.tf @@ -1,34 +1,62 @@ -provider "aws" { - region = var.aws_region -} - ############################# # Dynamic Variable Creation # ############################# -resource "null_resource" "create_cluster_node_name" { - count = "${var.number_of_nodes}" - - triggers = { - node_number = "${count.index + 1}" +locals { + cluster_node_names = formatlist("${var.cluster_name}-%02s", range(1, var.number_of_nodes + 1)) + ami_id = var.aws_image_id == "" || var.aws_image_id == "latest" ? data.aws_ami_ids.rubrik_cloud_cluster.ids[0] : var.aws_image_id + sg_ids = var.aws_cloud_cluster_nodes_sg_ids == "" ? [module.rubrik_nodes_sg.security_group_id] : concat(var.aws_cloud_cluster_nodes_sg_ids, [module.rubrik_nodes_sg.security_group_id]) + cluster_node_config = { + "instance_type" = var.aws_instance_type, + "ami_id" = local.ami_id, + "sg_ids" = local.sg_ids, + "subnet_id" = var.aws_subnet_id, + "key_pair_name" = local.aws_key_pair_name, + "disable_api_termination" = var.aws_disable_api_termination, + "iam_instance_profile" = module.iam_role.aws_iam_instance_profile.name, + "availability_zone" = data.aws_subnet.rubrik_cloud_cluster.availability_zone, + "tags" = var.aws_tags + } + cluster_node_ips = [for i in module.cluster_nodes.instances : i.private_ip] + cluster_disks = { + for v in setproduct(local.cluster_node_names, range(var.cluster_disk_count)) : + "${v[0]}-sd${substr("bcdefghi", v[1], 1)}" => { + "instance" = v[0], + "device" = "/dev/sd${substr("bcdefghi", v[1], 1)}" + "size" = var.cluster_disk_size + "type" = var.cluster_disk_type + } } + create_key_pair = var.create_key_pair ? 1 : 0 } -locals { - cluster_node_name = "${formatlist("${var.cluster_name}-%s", null_resource.create_cluster_node_name.*.triggers.node_number)}" +# RSA key of size 4096 bits +resource "tls_private_key" "cc-key" { + count = local.create_key_pair + algorithm = "RSA" + rsa_bits = 4096 +} - cluster_node_ips = "${aws_instance.rubrik_cluster.*.private_ip}" +resource "local_file" "cc-key-file" { + count = local.create_key_pair + content = tls_private_key.cc-key[0].private_key_pem + filename = var.private-key-file + file_permission = "400" } data "aws_subnet" "rubrik_cloud_cluster" { - id = "${var.aws_subnet_id}" + id = var.aws_subnet_id +} + +data "aws_vpc" "rubrik_cloud_cluster" { + id = data.aws_subnet.rubrik_cloud_cluster.vpc_id } data "aws_ami_ids" "rubrik_cloud_cluster" { - owners = ["679593333241"] + owners = var.aws_ami_owners filter { name = "name" - values = ["rubrik-mp-cc-*"] + values = var.aws_ami_filter } } @@ -36,132 +64,128 @@ data "aws_ami_ids" "rubrik_cloud_cluster" { # SSH KEY PAIR FOR INSTANCES # ############################## -resource "aws_key_pair" "rubrik_cloud_cluster" { - key_name = "${var.cluster_name}-key-pair" - public_key = "${var.aws_public_key}" -} - -######################################### -# Security Group for the Rubrik Cluster # -######################################### - -resource "aws_security_group" "rubrik_cloud_cluster" { - name = "${var.aws_vpc_security_group_name_cloud_cluster_nodes}" - description = "Allow hosts to talk to Rubrik Cloud Cluster" - vpc_id = "${data.aws_subnet.rubrik_cloud_cluster.vpc_id}" - - ingress { - description = "Intra cluster communication" - from_port = 0 - to_port = 0 - protocol = "-1" - self = true - } +module "aws_key_pair" { + source = "terraform-aws-modules/key-pair/aws" - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - ipv6_cidr_blocks = ["::/0"] - } + key_name = var.aws_key_pair_name == "" ? "${var.cluster_name}.key-pair" : var.aws_key_pair_name + public_key = var.aws_public_key == "" ? tls_private_key.cc-key[0].public_key_openssh : var.aws_public_key + create_key_pair = var.create_key_pair } -resource "aws_security_group" "rubrik_hosts" { - name = "${var.aws_vpc_security_group_name_cloud_cluster_hosts}" - description = "Allow Rubrik Cloud Cluster to communicate with hosts" - vpc_id = "${data.aws_subnet.rubrik_cloud_cluster.vpc_id}" - - ingress { - description = "Ports for Rubrik Backup Service (RBS)" - from_port = 12800 - to_port = 12801 - protocol = "tcp" - security_groups = ["${aws_security_group.rubrik_cloud_cluster.id}"] - } +locals { + aws_key_pair_name = var.aws_key_pair_name == "" ? module.aws_key_pair.key_pair_key_name : var.aws_key_pair_name } -resource "aws_security_group_rule" "rubrik_cloud_cluster_cli_admin" { - type = "ingress" - description = "CLI administration of the nodes" - from_port = 22 - to_port = 22 - protocol = "tcp" - security_group_id = "${aws_security_group.rubrik_cloud_cluster.id}" - source_security_group_id = "${aws_security_group.rubrik_hosts.id}" +######################################## +# S3 VPC Endpoint for Cloud Cluster ES # +######################################## + +module "s3_vpc_endpoint" { + source = "./modules/s3_vpc_endpoint" + + create = var.create_s3_vpc_endpoint + vpc_id = data.aws_subnet.rubrik_cloud_cluster.vpc_id + + tags = merge( + { Name = "${var.cluster_name}:ep" }, + var.aws_tags + ) } -resource "aws_security_group_rule" "rubrik_cloud_cluster_web_admin" { - type = "ingress" - description = "Web administration of the nodes" - from_port = 443 - to_port = 443 - protocol = "tcp" - security_group_id = "${aws_security_group.rubrik_cloud_cluster.id}" - source_security_group_id = "${aws_security_group.rubrik_hosts.id}" +###################################################################### +# Create, then configure, the Security Groups for the Rubrik Cluster # +###################################################################### +module "rubrik_nodes_sg" { + source = "terraform-aws-modules/security-group/aws" + + use_name_prefix = true + name = var.aws_vpc_cloud_cluster_nodes_sg_name == "" ? "${var.cluster_name}.sg" : var.aws_vpc_cloud_cluster_nodes_sg_name + description = "Allow hosts to talk to Rubrik Cloud Cluster and Cluster to talk to itself" + vpc_id = data.aws_subnet.rubrik_cloud_cluster.vpc_id + create = var.create_cloud_cluster_hosts_sg + tags = merge( + { name = "${var.cluster_name}:sg" }, + var.aws_tags + ) } -############################### -# Create EC2 Instances in AWS # -############################### +module "rubrik_nodes_sg_rules" { + source = "./modules/rubrik_nodes_sg" + sg_id = module.rubrik_nodes_sg.security_group_id + rubrik_hosts_sg_id = module.rubrik_hosts_sg.security_group_id + create = var.create_cloud_cluster_hosts_sg + cloud_cluster_nodes_admin_cidr = var.cloud_cluster_nodes_admin_cidr + tags = merge( + { name = "${var.cluster_name}:sg-rule" }, + var.aws_tags + ) + depends_on = [ + module.rubrik_hosts_sg + ] +} -resource "aws_instance" "rubrik_cluster" { - count = "${var.number_of_nodes}" - instance_type = "${var.aws_instance_type}" - ami = "${element(data.aws_ami_ids.rubrik_cloud_cluster.ids, 0)}" - vpc_security_group_ids = ["${aws_security_group.rubrik_cloud_cluster.id}"] - subnet_id = "${var.aws_subnet_id}" - key_name = "${aws_key_pair.rubrik_cloud_cluster.key_name}" +module "rubrik_hosts_sg" { + source = "terraform-aws-modules/security-group/aws" + + use_name_prefix = true + name = var.aws_vpc_cloud_cluster_hosts_sg_name == "" ? "${var.cluster_name}.sg" : var.aws_vpc_cloud_cluster_hosts_sg_name + description = "Allow Rubrik Cloud Cluster to talk to hosts, and hosts with this security group can talk to cluster" + vpc_id = data.aws_subnet.rubrik_cloud_cluster.vpc_id + create = var.create_cloud_cluster_hosts_sg + tags = merge( + { name = "${var.cluster_name}:sg" }, + var.aws_tags + ) +} - tags = { - Name = "${element(local.cluster_node_name, count.index)}" - } +module "rubrik_hosts_sg_rules" { + source = "./modules/rubrik_hosts_sg" + + sg_id = module.rubrik_hosts_sg.security_group_id + rubrik_nodes_sg_id = module.rubrik_nodes_sg.security_group_id + create = var.create_cloud_cluster_hosts_sg + tags = merge( + { name = "${var.cluster_name}:sg-rule" }, + var.aws_tags + ) + depends_on = [ + module.rubrik_nodes_sg + ] +} - disable_api_termination = "${var.aws_disable_api_termination}" - root_block_device { - encrypted = true - } - - ebs_block_device { - device_name = "/dev/sdb" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } +########################### +# Create S3 Bucket in AWS # +########################### +module "s3_bucket" { + source = "terraform-aws-modules/s3-bucket/aws" - ebs_block_device { - device_name = "/dev/sdc" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } + create_bucket = var.create_s3_bucket + bucket = var.s3_bucket_name == "" ? "${var.cluster_name}.bucket-do-not-delete" : var.s3_bucket_name + acl = "private" +} - ebs_block_device { - device_name = "/dev/sdd" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } +############################## +# Create IAM Role and Policy # +############################## +module "iam_role" { + source = "./modules/iam_role" + + bucket = module.s3_bucket + create = var.create_iam_role + role_name = var.aws_cloud_cluster_iam_role_name == "" ? "${var.cluster_name}.role" : var.aws_cloud_cluster_iam_role_name + role_policy_name = var.aws_cloud_cluster_iam_role_policy_name == "" ? "${var.cluster_name}.role-policy" : var.aws_cloud_cluster_iam_role_policy_name + instance_profile_name = var.aws_cloud_cluster_ec2_instance_profile_name == "" ? "${var.cluster_name}.instance-profile" : var.aws_cloud_cluster_ec2_instance_profile_name +} - ebs_block_device { - device_name = "/dev/sde" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } +############################### +# Create EC2 Instances in AWS # +############################### - ebs_block_device { - device_name = "/dev/sdf" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } +module "cluster_nodes" { + source = "./modules/rubrik_aws_instances" - ebs_block_device { - device_name = "/dev/sdg" - volume_type = "${var.cluster_disk_type}" - volume_size = "${var.cluster_disk_size}" - encrypted = true - } + node_names = local.cluster_node_names + node_config = local.cluster_node_config + disks = local.cluster_disks } \ No newline at end of file diff --git a/modules/iam_role/main.tf b/modules/iam_role/main.tf new file mode 100644 index 0000000..8936fc0 --- /dev/null +++ b/modules/iam_role/main.tf @@ -0,0 +1,67 @@ +resource "aws_iam_role" "rubrik_ec2_s3" { + count = var.create ? 1 : 0 + + name = var.role_name + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) + + tags = var.tags +} + +resource "aws_iam_role_policy" "rubrik_ec2_s3_policy" { + count = var.create ? 1 : 0 + name = var.role_policy_name + role = aws_iam_role.rubrik_ec2_s3[0].name + policy = jsonencode ({ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:AbortMultipartUpload", + "s3:DeleteObject*", + "s3:GetObject*", + "s3:ListMultipartUploadParts", + "s3:PutObject*" + ], + "Resource": "${var.bucket.s3_bucket_arn}/*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:GetBucket*", + "s3:ListBucket*" + ], + "Resource": "${var.bucket.s3_bucket_arn}" + } + ] + }) +} + +resource "aws_iam_instance_profile" "rubrik_ec2_s3_profile" { + count = var.create ? 1 : 0 + name = var.instance_profile_name + role = aws_iam_role.rubrik_ec2_s3[0].name + + tags = var.tags +} + +data "aws_iam_instance_profile" "rubrik_ec2_s3_profile" { + name = var.instance_profile_name + depends_on = [aws_iam_instance_profile.rubrik_ec2_s3_profile] +} + +output "aws_iam_instance_profile" { + value = data.aws_iam_instance_profile.rubrik_ec2_s3_profile +} \ No newline at end of file diff --git a/modules/iam_role/variables.tf b/modules/iam_role/variables.tf new file mode 100644 index 0000000..91018c8 --- /dev/null +++ b/modules/iam_role/variables.tf @@ -0,0 +1,25 @@ +variable "bucket" { + type = map(any) +} + +variable "create" { + type = bool + default = true +} + +variable "role_name" { + type = string +} + +variable "role_policy_name" { + type = string +} + +variable "instance_profile_name" { + type = string +} + +variable "tags" { + type = map(string) + default = { } +} \ No newline at end of file diff --git a/modules/rubrik_aws_instances/main.tf b/modules/rubrik_aws_instances/main.tf new file mode 100644 index 0000000..06441b7 --- /dev/null +++ b/modules/rubrik_aws_instances/main.tf @@ -0,0 +1,46 @@ +resource "aws_instance" "rubrik_cluster" { + for_each = var.node_names + instance_type = var.node_config.instance_type + ami = var.node_config.ami_id + vpc_security_group_ids = var.node_config.sg_ids + subnet_id = var.node_config.subnet_id + key_name = var.node_config.key_pair_name + lifecycle { + ignore_changes = [ami] + } + tags = merge({ + Name = each.value }, + var.node_config.tags + ) + + disable_api_termination = var.node_config.disable_api_termination + iam_instance_profile = var.node_config.iam_instance_profile + root_block_device { + encrypted = true + tags = {Name = "${each.value}-sda"} + } + +} + +resource "aws_ebs_volume" "ebs_block_device" { + for_each = var.disks + availability_zone = var.node_config.availability_zone + type = each.value.type + size = each.value.size + tags = merge( + {Name = each.key}, + var.node_config.tags + ) + encrypted = true +} + +resource "aws_volume_attachment" "ebs_att" { + for_each = var.disks + device_name = each.value.device + volume_id = aws_ebs_volume.ebs_block_device[each.key].id + instance_id = aws_instance.rubrik_cluster[each.value.instance].id +} + +output "instances" { + value = aws_instance.rubrik_cluster +} \ No newline at end of file diff --git a/modules/rubrik_aws_instances/variables.tf b/modules/rubrik_aws_instances/variables.tf new file mode 100644 index 0000000..fe25881 --- /dev/null +++ b/modules/rubrik_aws_instances/variables.tf @@ -0,0 +1,21 @@ +variable "node_names" { + type = set(string) +} + +variable "node_config" { + type = object({ + instance_type = string + ami_id = string + sg_ids = set(string) + subnet_id = string + key_pair_name = string + disable_api_termination = bool + iam_instance_profile = string + availability_zone = string + tags = map(string) + }) +} + +variable "disks" { + type = map(any) +} \ No newline at end of file diff --git a/modules/rubrik_hosts_sg/main.tf b/modules/rubrik_hosts_sg/main.tf new file mode 100644 index 0000000..94ca8af --- /dev/null +++ b/modules/rubrik_hosts_sg/main.tf @@ -0,0 +1,22 @@ +module "this" { + source = "terraform-aws-modules/security-group/aws" + + create_sg = false + security_group_id = var.sg_id + create = var.create + + ingress_with_source_security_group_id = [ + { + from_port = 12800 + to_port = 12801 + protocol = "tcp" + description = "Ports for Rubrik Backup Service (RBS)" + source_security_group_id = var.rubrik_nodes_sg_id + }, + ] + + tags = merge( + var.tags, + { "sg:purpose" = "rubrik-cluster-to-self" } + ) +} \ No newline at end of file diff --git a/modules/rubrik_hosts_sg/variables.tf b/modules/rubrik_hosts_sg/variables.tf new file mode 100644 index 0000000..b0b3d14 --- /dev/null +++ b/modules/rubrik_hosts_sg/variables.tf @@ -0,0 +1,17 @@ +variable "sg_id" { + type = string +} + +variable "create" { + type = bool + default = true +} + +variable "tags" { + type = map(string) + default = { } +} + +variable "rubrik_nodes_sg_id" { + type = string +} \ No newline at end of file diff --git a/modules/rubrik_nodes_sg/main.tf b/modules/rubrik_nodes_sg/main.tf new file mode 100644 index 0000000..e986663 --- /dev/null +++ b/modules/rubrik_nodes_sg/main.tf @@ -0,0 +1,63 @@ +module "this" { + source = "terraform-aws-modules/security-group/aws" + + create_sg = false + security_group_id = var.sg_id + create = var.create + + ingress_with_self = [{ rule = "all-all" }] + egress_rules = ["all-all"] + ingress_with_source_security_group_id = [ + { description = "HTTPS over TCP" + from_port = 443 + to_port = 443 + protocol = "tcp" + source_security_group_id = var.rubrik_hosts_sg_id + }, + { description = "SSH over TCP" + from_port = 22 + to_port = 22 + protocol = "tcp" + source_security_group_id = var.rubrik_hosts_sg_id + }, + { description = "NFS over TCP" + from_port = 2049 + to_port = 2049 + protocol = "tcp" + source_security_group_id = var.rubrik_hosts_sg_id + }, + { description = "SMB over TCP" + from_port = 445 + to_port = 445 + protocol = "tcp" + source_security_group_id = var.rubrik_hosts_sg_id + }, + { description = "SMB over TCP/UDP via NetBIOS" + from_port = 137 + to_port = 139 + protocol = -1 + source_security_group_id = var.rubrik_hosts_sg_id + } + ] + ingress_with_cidr_blocks = [ + { + from_port = 443 + to_port = 443 + protocol = "tcp" + description = "Admin port for web service" + cidr_blocks = var.cloud_cluster_nodes_admin_cidr + }, + { + from_port = 22 + to_port = 22 + protocol = "tcp" + description = "Admin port for ssh" + cidr_blocks = var.cloud_cluster_nodes_admin_cidr + } + ] + + tags = merge( + var.tags, + { "sg:purpose" = "rubrik-cluster-to-self" } + ) +} \ No newline at end of file diff --git a/modules/rubrik_nodes_sg/variables.tf b/modules/rubrik_nodes_sg/variables.tf new file mode 100644 index 0000000..bd955a0 --- /dev/null +++ b/modules/rubrik_nodes_sg/variables.tf @@ -0,0 +1,21 @@ +variable "sg_id" { + type = string +} + +variable "create" { + type = bool + default = true +} + +variable "tags" { + type = map(string) + default = {} +} + +variable "rubrik_hosts_sg_id" { + type = string +} + +variable "cloud_cluster_nodes_admin_cidr" { + type = string +} \ No newline at end of file diff --git a/modules/s3_vpc_endpoint/main.tf b/modules/s3_vpc_endpoint/main.tf new file mode 100644 index 0000000..d123041 --- /dev/null +++ b/modules/s3_vpc_endpoint/main.tf @@ -0,0 +1,22 @@ +locals { + get_endpoint_data = var.create == true ? 1 : 0 +} +data "aws_region" "current" {} + +resource "aws_vpc_endpoint" "s3_endpoint" { + count = local.get_endpoint_data + vpc_id = var.vpc_id + service_name = "com.amazonaws.${data.aws_region.current.id}.s3" + vpc_endpoint_type = "Gateway" + + tags = var.tags +} + +data "aws_vpc_endpoint" "this" { + count = local.get_endpoint_data + vpc_id = var.vpc_id + id = aws_vpc_endpoint.s3_endpoint[0].id + depends_on = [ + aws_vpc_endpoint.s3_endpoint + ] +} \ No newline at end of file diff --git a/modules/s3_vpc_endpoint/output.tf b/modules/s3_vpc_endpoint/output.tf new file mode 100644 index 0000000..afede69 --- /dev/null +++ b/modules/s3_vpc_endpoint/output.tf @@ -0,0 +1,4 @@ +output "endpoint" { + description = "Array containing the full resource object and attributes for all endpoints created" + value = data.aws_vpc_endpoint.this +} \ No newline at end of file diff --git a/modules/s3_vpc_endpoint/variables.tf b/modules/s3_vpc_endpoint/variables.tf new file mode 100644 index 0000000..c5c214d --- /dev/null +++ b/modules/s3_vpc_endpoint/variables.tf @@ -0,0 +1,22 @@ +variable "create" { + default = true +} + +variable "vpc_id" { + type = string +} + +variable "route_table_ids" { + type = list(string) + default = null +} + +variable "tags" { + type = map(string) + default = { Name = "s3-vpc-endpoint" } +} + +variable "endpoint_name" { + type = string + default = null +} \ No newline at end of file diff --git a/output.tf b/output.tf index b6266d8..aed008e 100644 --- a/output.tf +++ b/output.tf @@ -1,3 +1,15 @@ output "rubrik_cloud_cluster_ip_addrs" { - value = aws_instance.rubrik_cluster.*.private_ip + value = local.cluster_node_ips +} + +output "rubrik_hosts_sg_id" { + value = module.rubrik_hosts_sg.security_group_id +} + +output "s3_bucket" { + value = module.s3_bucket.s3_bucket_id +} + +output "private_key_file" { + value = var.create_key_pair ? var.private-key-file : null } \ No newline at end of file diff --git a/providers.tf b/providers.tf index b7bdbfd..94d6313 100644 --- a/providers.tf +++ b/providers.tf @@ -1,10 +1,13 @@ terraform { -} -terraform { - required_version = ">= 0.15.4" + required_version = ">= 1.2.0" required_providers { aws = { - source = "hashicorp/aws" + source = "hashicorp/aws" } } +} + +# Configure the AWS Provider +provider "aws" { + region = var.aws_region } \ No newline at end of file diff --git a/variables.tf b/variables.tf index e2e2318..8b6e2ab 100644 --- a/variables.tf +++ b/variables.tf @@ -1,8 +1,10 @@ +# Instance/Node Settings variable "aws_region" { description = "The region to deploy Rubrik Cloud Cluster nodes." } + variable "aws_instance_type" { - description = "The type of instance to use as Rubrik Cloud Cluster nodes." + description = "The type of instance to use as Rubrik Cloud Cluster nodes. CC-ES requires m5.4xlarge." default = "m5.4xlarge" } @@ -11,40 +13,154 @@ variable "aws_disable_api_termination" { default = true } -variable "aws_vpc_security_group_name_cloud_cluster_nodes" { +variable "aws_tags" { + description = "Tags to add to the AWS resources that this Terraform script creates, including the Rubrik cluster nodes." + type = map(string) + default = {} +} + +variable "number_of_nodes" { + description = "The total number of nodes in Rubrik Cloud Cluster." + default = 3 +} + +variable "aws_ami_owners" { + description = "AWS marketplace account(s) that owns the Rubrik Cloud Cluster AMIs. Use [\"345084742485\"] for AWS GovCloud." + type = set(string) + default = ["679593333241"] +} + +variable "aws_ami_filter" { + description = "Cloud Cluster AWS AMI name pattern(s) to search for. Use [\"rubrik-mp-cc-*\"]. Where is the major version of CDM. Ex. [\"rubrik-mp-cc-7\"]" + type = set(string) +} + +variable "aws_image_id" { + description = "AWS Image ID to deploy. Set to 'latest' or leave blank to deploy the latest version from the marketplace." + type = string + default = "latest" +} + +variable "create_key_pair" { + description = "If true, a new AWS SSH Key-Pair will be created using the aws_key_pair_name and aws_public_key settings." + type = bool + default = true +} + +variable "aws_key_pair_name" { + description = "Name for the AWS SSH Key-Pair being created or the existing AWS SSH Key-Pair being used." + type = string + default = "" +} + +variable "aws_public_key" { + description = "The public key material needed to create an AWS Key-Pair for use with Rubrik Cloud Cluster. " + sensitive = true + default = "" +} +variable "private-key-file" { + description = "If a new AWS SSH Key-Pair is generated, the name of the file to save the private key material in." + type = string + default = "./.terraform/cc-key.pem" +} + +# Network Settings +variable "create_cloud_cluster_nodes_sg" { + description = "If true, creates a new Security Group for node to node traffic within the Rubrik cluster." + type = bool + default = true +} +variable "aws_vpc_cloud_cluster_nodes_sg_name" { description = "The name of the security group to create for Rubrik Cloud Cluster to use." - default = "Rubrik Cloud Cluster" + default = "Rubrik Cloud Cluster Nodes" } -variable "aws_vpc_security_group_name_cloud_cluster_hosts" { +variable "cloud_cluster_nodes_admin_cidr" { + description = "The CIDR range for the systems used to administer the Cloud Cluster via SSH and HTTPS." + type = string + default = "0.0.0.0/0" +} +variable "create_cloud_cluster_hosts_sg" { + description = "If true, creates a new Security Group for node to host traffic from the Rubrik cluster." + type = bool + default = true +} +variable "aws_vpc_cloud_cluster_hosts_sg_name" { description = "The name of the security group to create for Rubrik Cloud Cluster to communicate with EC2 instances." default = "Rubrik Cloud Cluster Hosts" } +variable "aws_cloud_cluster_nodes_sg_ids" { + description = "Additional security groups to add to Rubrik cluster nodes." + type = list(string) + default = [] +} + variable "aws_subnet_id" { description = "The VPC Subnet ID to launch Rubrik Cloud Cluster in." } -variable "aws_public_key" { - description = "The public key material needed to create an AWS key pair for use with Rubrik Cloud Cluster." - sensitive = true +# Storage Settings +variable "cluster_disk_type" { + description = "Disk type for the data disks (st1, sc1 or gp2). Use gp2 for CC-ES. Use sc1 for 48TB CC nodes. Use st1 for all others. " + default = "gp2" } -variable "number_of_nodes" { - description = "The total number of nodes in Rubrik Cloud Cluster." - default = 4 +variable "cluster_disk_size" { + description = "The size (in GB) of each data disk on each node. Cloud Cluster ES only requires 1 512 GB disk per node." + default = "512" } -variable "cluster_disk_type" { - description = "The disk type to use for Rubrik Cloud Cluster data disks (sc1 or st1). NOTE: st1 disks require six 8TB disks." - default = "st1" +variable "cluster_disk_count" { + description = "The number of disks for each node in the cluster. Set to 1 to use with S3 storage for Cloud Cluster ES." + type = number + default = 1 } -variable "cluster_disk_size" { - description = "The size of each the three data disks in each node." - default = "1024" +# Cloud Cluster ES Settings +variable "create_iam_role" { + description = "If true, create required IAM role, role policy, and instance profile needed for Cloud Cluster ES." + type = bool + default = true +} + +variable "aws_cloud_cluster_iam_role_name" { + description = "AWS IAM Role name for Cloud Cluster ES. If blank a name will be auto generated. Required if create_iam_role is false." + type = string + default = "" } +variable "aws_cloud_cluster_iam_role_policy_name" { + description = "AWS IAM Role policy name for Cloud Cluster ES if create_iam_role is true. If blank a name will be auto generated." + type = string + default = "" +} + +variable "aws_cloud_cluster_ec2_instance_profile_name" { + description = "AWS EC2 Instance Profile name that links the IAM Role to Cloud Cluster ES. If blank a name will be auto generated." + type = string + default = "" +} + +variable "create_s3_bucket" { + description = "If true, create am S3 bucket for Cloud Cluster ES data storage." + type = bool + default = true +} + +variable "s3_bucket_name" { + description = "Name of the S3 bucket to use with Cloud Cluster ES data storage. If blank a name will be auto generated." + type = string + default = "" +} + +variable "create_s3_vpc_endpoint" { + description = "If true, create a VPC Endpoint and S3 Endpoint Service for Cloud Cluster ES. " + type = bool + default = true +} + +# Bootstrap Settings variable "cluster_name" { description = "Unique name to assign to the Rubrik Cloud Cluster. This will also be used to populate the EC2 instance name tag. For example, rubrik-cloud-cluster-1, rubrik-cloud-cluster-2 etc." default = "rubrik-cloud-cluster" @@ -54,19 +170,21 @@ variable "admin_email" { description = "The Rubrik Cloud Cluster sends messages for the admin account to this email address." } -variable admin_password { +variable "admin_password" { description = "Password for the Rubrik Cloud Cluster admin account." default = "RubrikGoForward" } variable "dns_search_domain" { - type = list + type = list(any) description = "List of search domains that the DNS Service will use to resolve hostnames that are not fully qualified." + default = [] } variable "dns_name_servers" { - type = list + type = list(any) description = "List of the IPv4 addresses of the DNS servers." + default = ["169.254.169.253"] } variable "ntp_servers" { @@ -77,4 +195,4 @@ variable "ntp_servers" { variable "timeout" { description = "The number of seconds to wait to establish a connection the Rubrik cluster before returning a timeout error." default = 15 -} +} \ No newline at end of file