From 9698d1aeffde54ae707fdae0c4efe39ab27a7d64 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Wed, 7 Aug 2024 18:16:21 +0000 Subject: [PATCH] Add Elastio terraform deployment automation example --- elastio-terraform-deployment/README.md | 62 ++++++++++++ elastio-terraform-deployment/module/main.tf | 95 +++++++++++++++++++ .../module/providers.tf | 12 +++ .../module/variables.tf | 43 +++++++++ 4 files changed, 212 insertions(+) create mode 100644 elastio-terraform-deployment/README.md create mode 100644 elastio-terraform-deployment/module/main.tf create mode 100644 elastio-terraform-deployment/module/providers.tf create mode 100644 elastio-terraform-deployment/module/variables.tf diff --git a/elastio-terraform-deployment/README.md b/elastio-terraform-deployment/README.md new file mode 100644 index 0000000..c6c7bc8 --- /dev/null +++ b/elastio-terraform-deployment/README.md @@ -0,0 +1,62 @@ +# Elastio terraform deployment + +This project presents an example of how you may automate the deployment of the Elastio stack in your AWS account. + +## Obtain a personal access token (PAT) + +First of all, you'll need a secret PAT token to authenticate your Elastio installation with the Elastio Portal. You can generate one by following the steps below. + +1. Open the [Elastio Portal](https://login.elastio.com/) in your web browser. +2. Click on the profile button at the top right corner of the page. +3. Go to the `API access` tab. +4. Click on `Add New Access Token`. +5. Enter the name for the token, for example `Elastio deployment`. +6. Select the scope `Sources: Write` for the token. +7. Click on `Generate Token`. +8. Copy the generated token. +9. *Optional step.* Save the token in a secure place like 1Password or any other secret management system of your choice. This way you won't lose it. + +## Add Elastio to your Terraform + +There is a terraform module under the `module` directory. It deploys all the necessary resources for Elastio to operate. It includes the following: + +- AWS Cloudformation stack named `elastio-account-level-stack`, which is deployed once per AWS account and contains the required IAM resources +- Elastio Cloud Connector stack deployed by Elastio Portal via a REST API call. It contains Lambda functions, DynamoDB databases, S3 buckets, AWS Batch compute environments and other non-IAM resources. +- *Optional.* A NAT provisioning stack that deploys NAT gateways in the private subnets where Elastio scan job workers run. This is necessary only if you deploy Elastio into private subnets that don't have outbound Internet access already. Alternatively you can deploy your own NAT gateway if you want to. + +Add this terraform module to your terraform project add specify the necessary input variables. Here you'll need to pass the PAT token you [generated earlier](#obtain-a-personal-access-token-pat), specify your Elastio tenant name and the list of regions with VPC/subnet configurations where you want to deploy Elastio. + +Here is an example usage of the module + +```tf +provider "aws" {} +provider "http" {} + +module "elastio" { + source = "../module" + elastio_pat = "{pat_token_from_elastio_portal}" + elastio_tenant = "mycompany.app.elastio.com" + elastio_cloud_connectors = [ + { + region = "us-east-2" + vpc_id = "vpc-0001" + subnet_ids = [ + "subnet-0001", + "subnet-0002" + ] + }, + { + region = "us-east-1" + vpc_id = "vpc-0002" + subnet_ids = [ + "subnet-0003", + "subnet-0004", + ] + } + ] + + # This input is optional. Here you can specify the version of the NAT provisioning stack. + # If you don't need it, just omit this input variable. + elastio_nat_provision_stack = "v4" +} +``` diff --git a/elastio-terraform-deployment/module/main.tf b/elastio-terraform-deployment/module/main.tf new file mode 100644 index 0000000..6557c49 --- /dev/null +++ b/elastio-terraform-deployment/module/main.tf @@ -0,0 +1,95 @@ +locals { + elastio_endpoint = "https://${var.elastio_tenant}/public-api/v1" + headers = { + Authorization = "Bearer ${var.elastio_pat}" + } +} + +data "http" "cloudformation_template" { + url = "${local.elastio_endpoint}/cloudformation-template" + request_headers = local.headers + + retry { + attempts = 10 + max_delay_ms = 10000 + } + + lifecycle { + postcondition { + condition = self.status_code >= 200 && self.status_code < 300 + error_message = "Status code invalid" + } + } +} + +resource "aws_cloudformation_stack" "elastio_account_level_stack" { + name = "elastio-account-level-stack" + template_url = data.http.cloudformation_template.response_body + tags = { + "elastio:resource" = "true" + } + capabilities = ["CAPABILITY_NAMED_IAM"] +} + +resource "aws_cloudformation_stack" "elastio_nat_provision_stack" { + count = var.elastio_nat_provision_stack == null ? 0 : 1 + + name = "elastio-nat-provision-lambda" + template_url = join( + "/", + [ + "https://elastio-prod-artifacts-us-east-2.s3.us-east-2.amazonaws.com", + "contrib/elastio-nat-provision-lambda/${var.elastio_nat_provision_stack}", + "cloudformation-lambda.yaml" + ] + ) + tags = { + "elastio:resource" = "true" + } + capabilities = ["CAPABILITY_IAM"] +} + +data "aws_caller_identity" "current" {} + +locals { + elastio_cloud_connector_deploy_requests = [ + for connector in var.elastio_cloud_connectors : merge( + connector, + { account_id = data.aws_caller_identity.current.account_id }, + ) + ] +} + +resource "terraform_data" "elastio_cloud_connector" { + for_each = { + for request in local.elastio_cloud_connector_deploy_requests : + request.region => request + } + + input = each.value + triggers_replace = each.value + + provisioner "local-exec" { + command = <