From 9bcc3c15314d857d39c7fb86498dd80f866cf761 Mon Sep 17 00:00:00 2001 From: Niklas Schmidtmer Date: Mon, 18 Dec 2023 15:19:37 +0100 Subject: [PATCH] Make Prometheus SSL optional (#98) * Allow disabling SSL for Prometheus * Update dependencies * Install nano by default * Use RedHat Enterprise Linux 9 for Prometheus repository * Add tests for input validation * Install locust by default * Run terraform test on GitHub --- .github/workflows/tflint.yml | 16 ++++ aws/.terraform.lock.hcl | 114 +++++++++++------------ aws/.tflint.hcl | 2 +- aws/README.md | 94 +++++++++++-------- aws/ec2.tf | 22 +++-- aws/ec2_utility.tf | 51 ++++++++-- aws/main.tf | 4 +- aws/scripts/cloud-init-cratedb-rpm.tftpl | 13 +-- aws/scripts/cloud-init-cratedb-tar.tftpl | 12 +-- aws/scripts/cloud-init-utilities.tftpl | 28 ++---- aws/scripts/user_provisioning.sh | 18 ++++ aws/tests/variables.tftest.hcl | 58 ++++++++++++ aws/variables.tf | 10 ++ 13 files changed, 287 insertions(+), 155 deletions(-) create mode 100755 aws/scripts/user_provisioning.sh create mode 100644 aws/tests/variables.tftest.hcl diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml index f0d580c..b886189 100644 --- a/.github/workflows/tflint.yml +++ b/.github/workflows/tflint.yml @@ -19,6 +19,22 @@ jobs: - run: tflint --init - run: tflint --format compact + test_aws: + runs-on: ubuntu-latest + defaults: + run: + working-directory: aws + steps: + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + - run: terraform init + - shell: bash + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + terraform test + lint_azure: runs-on: ubuntu-latest defaults: diff --git a/aws/.terraform.lock.hcl b/aws/.terraform.lock.hcl index 5b3b0ba..63c56e5 100644 --- a/aws/.terraform.lock.hcl +++ b/aws/.terraform.lock.hcl @@ -2,84 +2,84 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "5.7.0" - constraints = "~> 5.7" + version = "5.31.0" + constraints = "~> 5.29" hashes = [ - "h1:aa0gGxD4NVirhzUUbEngnG2Ag6fAsPMjIsivd/f2QVM=", - "zh:03240d7fc041d5331db7fd5f2ca4fe031321d07d2a6ca27085c5020dae13f211", - "zh:0b5252b14c354636fe0348823195dd901b457de1a033015f4a7d11cfe998c766", - "zh:2bfb62325b0487be8d1850a964f09cca0d45148faec577459c2a24334ec9977b", - "zh:2f9e317ffc57d2b5117cfe8dc266f88aa139b760bc93d8adeed7ad533a78b5a3", - "zh:36512725c9d7c559927b98fead04be58494a3a997e5270b905a75a468e307427", - "zh:5483e696d3ea764f746d3fe439f7dcc49001c3c774122d7baa51ce01011f0075", - "zh:5967635cc14f969ea26622863a2e3f9d6a7ddd3e7d35a29a7275c5e10579ac8c", - "zh:7e63c94a64af5b7aeb36ea6e3719962f65a7c28074532c02549a67212d410bb8", - "zh:8a7d5f33b11a3f5c7281413b431fa85de149ed8493ec1eea73d50d2d80a475e6", - "zh:8e2ed2d986aaf590975a79a2f6b5e60e0dc7d804ab01a8c03ab181e41cfe9b0f", + "h1:2eauBmfftzGMpzFQn9aHSXiyaO3Ve5cnihmXcKGGpgU=", + "zh:0cdb9c2083bf0902442384f7309367791e4640581652dda456f2d6d7abf0de8d", + "zh:2fe4884cb9642f48a5889f8dff8f5f511418a18537a9dfa77ada3bcdad391e4e", + "zh:36d8bdd72fe61d816d0049c179f495bc6f1e54d8d7b07c45b62e5e1696882a89", + "zh:539dd156e3ec608818eb21191697b230117437a58587cbd02ce533202a4dd520", + "zh:6a53f4b57ac4eb3479fc0d8b6e301ca3a27efae4c55d9f8bd24071b12a03361c", + "zh:6faeb8ff6792ca7af1c025255755ad764667a300291cc10cea0c615479488c87", + "zh:7d9423149b323f6d0df5b90c4d9029e5455c670aea2a7eb6fef4684ba7eb2e0b", + "zh:8235badd8a5d0993421cacf5ead48fac73d3b5a25c8a68599706a404b1f70730", + "zh:860b4f60842b2879c5128b7e386c8b49adeda9287fed12c5cd74861bb659bbcd", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9c7b8ca1b17489f16a6d0f1fc2aa9c130978ea74c9c861d8435410567a0a888f", - "zh:a54385896a70524063f0c5420be26ff6f88909bd8e6902dd3e922577b21fd546", - "zh:aecd3a8fb70b938b58d93459bfb311540fd6aaf981924bf34abd48f953b4be0d", - "zh:f3de076fa3402768d27af0187c6a677777b47691d1f0f84c9b259ff66e65953e", + "zh:b021fceaf9382c8fe3c6eb608c24d01dce3d11ba7e65bb443d51ca9b90e9b237", + "zh:b38b0bfc1c69e714e80cf1c9ea06e687ee86aa9f45694be28eb07adcebbe0489", + "zh:c972d155f6c01af9690a72adfb99cfc24ef5ef311ca92ce46b9b13c5c153f572", + "zh:e0dd29920ec84fdb6026acff44dcc1fb1a24a0caa093fa04cdbc713d384c651d", + "zh:e3127ebd2cb0374cd1808f911e6bffe2f4ac4d84317061381242353f3a7bc27d", ] } provider "registry.terraform.io/hashicorp/cloudinit" { - version = "2.3.2" + version = "2.3.3" constraints = "~> 2.3" hashes = [ - "h1:Ar/DAbZQ9Nsj0BrqX6camrEE6U+Yq4E87DCNVqxqx8k=", - "zh:2487e498736ed90f53de8f66fe2b8c05665b9f8ff1506f751c5ee227c7f457d1", - "zh:3d8627d142942336cf65eea6eb6403692f47e9072ff3fa11c3f774a3b93130b3", - "zh:434b643054aeafb5df28d5529b72acc20c6f5ded24decad73b98657af2b53f4f", - "zh:436aa6c2b07d82aa6a9dd746a3e3a627f72787c27c80552ceda6dc52d01f4b6f", - "zh:458274c5aabe65ef4dbd61d43ce759287788e35a2da004e796373f88edcaa422", - "zh:54bc70fa6fb7da33292ae4d9ceef5398d637c7373e729ed4fce59bd7b8d67372", + "h1:ZmQ97fIcPW7hj/vynRB4zbtObK0Z/LVJPvCwlNd78zA=", + "zh:0bd6ee14ca5cf0f0c83d3bb965346b1225ccd06a6247e80774aaaf54c729daa7", + "zh:3055ad0dcc98de1d4e45b72c5889ae91b62f4ae4e54dbc56c4821be0fdfbed91", + "zh:32764cfcff0d7379ca8b7dde376ac5551854d454c5881945f1952b785a312fa2", + "zh:55c2a4dc3ebdeaa1dec3a36db96dab253c7fa10b9fe1209862e1ee77a01e0aa1", + "zh:5c71f260ba5674d656d12f67cde3bb494498e6b6b6e66945ef85688f185dcf63", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:893ba267e18749c1a956b69be569f0d7bc043a49c3a0eb4d0d09a8e8b2ca3136", - "zh:95493b7517bce116f75cdd4c63b7c82a9d0d48ec2ef2f5eb836d262ef96d0aa7", - "zh:9ae21ab393be52e3e84e5cce0ef20e690d21f6c10ade7d9d9d22b39851bfeddc", - "zh:cc3b01ac2472e6d59358d54d5e4945032efbc8008739a6d4946ca1b621a16040", - "zh:f23bfe9758f06a1ec10ea3a81c9deedf3a7b42963568997d84a5153f35c5839a", + "zh:9617280a853ec7caedb8beb7864e4b29faf9c850a453283980c28fccef2c493d", + "zh:ac8bda21950f8dddade3e9bc15f7bcfdee743738483be5724169943cafa611f5", + "zh:ba9ab567bbe63dee9197a763b3104ea9217ba27449ed54d3afa6657f412e3496", + "zh:effd1a7e34bae3879c02f03ed3afa979433a518e11de1f8afd35a8710231ac14", + "zh:f021538c86d0ac250d75e59efde6d869bbfff711eb744c8bddce79d2475bf46d", + "zh:f1e3984597948a2103391a26600e177b19f16a5a4c66acee27a4343fb141571f", ] } provider "registry.terraform.io/hashicorp/random" { - version = "3.5.1" - constraints = "~> 3.4" + version = "3.6.0" + constraints = "~> 3.5" hashes = [ - "h1:sZ7MTSD4FLekNN2wSNFGpM+5slfvpm5A/NLVZiB7CO0=", - "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64", - "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d", - "zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831", - "zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3", - "zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f", + "h1:p6WG1IPHnqx1fnJVKNjv733FBaArIugqy58HRZnpPCk=", + "zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d", + "zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211", + "zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829", + "zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d", + "zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b", - "zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2", - "zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865", - "zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03", - "zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602", - "zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014", + "zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17", + "zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21", + "zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839", + "zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0", + "zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c", + "zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e", ] } provider "registry.terraform.io/hashicorp/tls" { - version = "4.0.4" + version = "4.0.5" constraints = "~> 4.0" hashes = [ - "h1:Wd3RqmQW60k2QWPN4sK5CtjGuO1d+CRNXgC+D4rKtXc=", - "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55", - "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848", - "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be", - "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5", - "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe", - "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e", - "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48", - "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8", - "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60", - "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e", - "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316", + "h1:yLqz+skP3+EbU3yyvw8JqzflQTKDQGsC9QyZAg+S4dg=", + "zh:01cfb11cb74654c003f6d4e32bbef8f5969ee2856394a96d127da4949c65153e", + "zh:0472ea1574026aa1e8ca82bb6df2c40cd0478e9336b7a8a64e652119a2fa4f32", + "zh:1a8ddba2b1550c5d02003ea5d6cdda2eef6870ece86c5619f33edd699c9dc14b", + "zh:1e3bb505c000adb12cdf60af5b08f0ed68bc3955b0d4d4a126db5ca4d429eb4a", + "zh:6636401b2463c25e03e68a6b786acf91a311c78444b1dc4f97c539f9f78de22a", + "zh:76858f9d8b460e7b2a338c477671d07286b0d287fd2d2e3214030ae8f61dd56e", + "zh:a13b69fb43cb8746793b3069c4d897bb18f454290b496f19d03c3387d1c9a2dc", + "zh:a90ca81bb9bb509063b736842250ecff0f886a91baae8de65c8430168001dad9", + "zh:c4de401395936e41234f1956ebadbd2ed9f414e6908f27d578614aaa529870d4", + "zh:c657e121af8fde19964482997f0de2d5173217274f6997e16389e7707ed8ece8", + "zh:d68b07a67fbd604c38ec9733069fbf23441436fecf554de6c75c032f82e1ef19", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } diff --git a/aws/.tflint.hcl b/aws/.tflint.hcl index a0bbf65..7cc1038 100644 --- a/aws/.tflint.hcl +++ b/aws/.tflint.hcl @@ -1,6 +1,6 @@ plugin "aws" { enabled = true - version = "0.24.1" + version = "0.28.0" source = "github.com/terraform-linters/tflint-ruleset-aws" } diff --git a/aws/README.md b/aws/README.md index 617bdaf..03ffbe2 100644 --- a/aws/README.md +++ b/aws/README.md @@ -1,4 +1,5 @@ # CrateDB cluster on EC2 instances using Terraform + This Terraform configuration will launch a CrateDB cluster on AWS. It consists of a public-facing load lancer with and a set of EC2 instances. ![AWS architecture](aws_architecture.png) @@ -6,91 +7,102 @@ This Terraform configuration will launch a CrateDB cluster on AWS. It consists o The provided configuration is meant as an easy way to get started. It is not necessarily production-ready in all aspects, such as backups, high availability, and security. Please clone and extend the configuration to fit your individual needs, if needed. ## Setup + The Terraform configuration generates by default an individual self-signed SSL certificate. If `crate.ssl_enable` is set to false, SSL will be disabled. For a full list of available variables (including disk configuration), please see [variables.tf](variables.tf). The main setup consists of the following steps: + 1. Crate a new `main.tf` Terraform configuration, referencing the CrateDB module: - ```hcl - module "cratedb-cluster" { - source = "git@github.com:crate/crate-terraform.git//aws" + ```hcl + module "cratedb-cluster" { + source = "git@github.com:crate/crate-terraform.git//aws" - # Global configuration items for naming/tagging resources - config = { - project_name = "example-project" - environment = "test" - owner = "Crate.IO" - team = "Customer Engineering" - } + # Global configuration items for naming/tagging resources + config = { + project_name = "example-project" + environment = "test" + owner = "Crate.IO" + team = "Customer Engineering" + } - # CrateDB-specific configuration - crate = { - # Java Heap size in GB available to CrateDB - heap_size_gb = 2 + # CrateDB-specific configuration + crate = { + # Java Heap size in GB available to CrateDB + heap_size_gb = 2 - cluster_name = "crate-cluster" + cluster_name = "crate-cluster" - # The number of nodes the cluster will consist of - cluster_size = 2 + # The number of nodes the cluster will consist of + cluster_size = 2 - # Enables a self-signed SSL certificate - ssl_enable = true - } + # Enables a self-signed SSL certificate + ssl_enable = true + } - # The disk size in GB to use for CrateDB's data directory - disk_size_gb = 512 + # The disk size in GB to use for CrateDB's data directory + disk_size_gb = 512 - # The AWS region - region = "eu-central-1" + # The AWS region + region = "eu-central-1" - # The VPC to deploy to - vpc_id = "vpc-1234567" + # The VPC to deploy to + vpc_id = "vpc-1234567" - # Applicable subnets of the VPC - subnet_ids = ["subnet-123456", "subnet-123457"] + # Applicable subnets of the VPC + subnet_ids = ["subnet-123456", "subnet-123457"] - # The corresponding availability zones of above subnets - availability_zones = ["eu-central-1b", "eu-central-1a"] + # The corresponding availability zones of above subnets + availability_zones = ["eu-central-1b", "eu-central-1a"] - # The SSH key pair for EC2 instances - ssh_keypair = "cratedb-cluster" + # The SSH key pair for EC2 instances + ssh_keypair = "cratedb-cluster" - # Enable SSH access to EC2 instances - ssh_access = true - } + # Enable SSH access to EC2 instances + ssh_access = true + } - output "cratedb" { - value = module.cratedb-cluster - sensitive = true - } -``` + output "cratedb" { + value = module.cratedb-cluster + sensitive = true + } + ``` 2. Run `terraform init` to download and install all needed providers. ## Execution + To run the Terraform configuration: + 1. Run `terraform plan` to validate the planned resource creation 2. Run `terraform apply` to execute the plan 3. Run `terraform output -json` to view the cleartext output, such as the CrateDB URL and login credentials ## Accessing CrateDB + The above last-mentioned step will output all needed information to connect to CrateDB. This includes the publicly accessible URL of the load balancer, as well as login credentials. On opening this URL in a browser, an HTTP Basic Auth appears. Please note that it might take a couple of minutes before instances are fully provisioned and CrateDB becomes accessible. ## Accessing EC2 instances + Your EC2 instances will only have a public IP address if the corresponding VPC subnet is configured to [auto-assign](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html) public IP addresses. Connecting via SSH can be done using the `ec2-user` account and the configured key pair. In the default configuration, SSH access is enabled in the security group. It can be disabled if needed via the `ssh_access` variable. ## Utility EC2 instance + Optionally, you can provision an additional EC2 instance that will not run CrateDB. Instead, it can be used to run benchmarks or other client applications. It is located in the same VPC and subnet as the CrateDB nodes for optimal network latency. Connect to the EC2 instance using the `ec2-user` account and the configured key pair. The host and port for SSH connections is available via the output variables `utility_vm_host` and `utility_vm_port`. ## Crate JMX Exporter + The [Crate JMX Exporter](https://github.com/crate/jmx_exporter) exposes monitoring metrics in the Prometheus format. It is available through the load balancer on port 8080. Independent of the `crate.ssl_enable` setting, the endpoint is always accessible through `http`. ## Prometheus -[Prometheus](https://prometheus.io) is capturing the export of the Crate JMX Exporter. It is available through the load balancer on port 9090 through `https` with a self-signed certificate. Basic authentication is in place with the user `admin` and the password provided in the output variable `utility_vm_prometheus_password`. \ No newline at end of file + +[Prometheus](https://prometheus.io) is capturing the export of the Crate JMX Exporter. It is available through the load balancer on port 9090 through `https` with a self-signed certificate. Basic authentication is in place with the user `admin` and the password provided in the output variable `utility_vm_prometheus_password`. + +Specify `prometheus_ssl = false` if you prefer Prometheus not to use SSL. diff --git a/aws/ec2.tf b/aws/ec2.tf index 0d3c958..3ec7f1b 100644 --- a/aws/ec2.tf +++ b/aws/ec2.tf @@ -40,16 +40,18 @@ data "cloudinit_config" "config" { content_type = "text/cloud-config" content = templatefile("${path.module}/scripts/cloud-init-cratedb-${var.cratedb_tar_download_url == null ? "rpm" : "tar"}.tftpl", { - crate_download_url = var.cratedb_tar_download_url - crate_user = local.config.crate_username - crate_pass = local.cratedb_password - crate_heap_size = var.crate.heap_size_gb - crate_cluster_name = var.crate.cluster_name - crate_cluster_size = var.crate.cluster_size - crate_nodes_ips = indent(12, yamlencode(aws_network_interface.interface[*].private_ip)) - crate_ssl_enable = var.crate.ssl_enable - crate_ssl_certificate = base64encode(tls_self_signed_cert.ssl.cert_pem) - crate_ssl_private_key = base64encode(tls_private_key.ssl.private_key_pem) + user_provisioning_file = indent(6, file(("${path.module}/scripts/user_provisioning.sh"))) + crate_download_url = var.cratedb_tar_download_url + crate_user = local.config.crate_username + crate_pass = local.cratedb_password + crate_heap_size = var.crate.heap_size_gb + crate_cluster_name = var.crate.cluster_name + crate_cluster_size = var.crate.cluster_size + crate_nodes_ips = indent(12, yamlencode(aws_network_interface.interface[*].private_ip)) + crate_ssl_enable = var.crate.ssl_enable + crate_protocol = var.crate.ssl_enable ? "https" : "http" + crate_ssl_certificate = base64encode(tls_self_signed_cert.ssl.cert_pem) + crate_ssl_private_key = base64encode(tls_private_key.ssl.private_key_pem) } ) } diff --git a/aws/ec2_utility.tf b/aws/ec2_utility.tf index 812410c..93d9fd1 100644 --- a/aws/ec2_utility.tf +++ b/aws/ec2_utility.tf @@ -3,6 +3,30 @@ locals { ssh_alternative_port = 2222 prometheus_password = var.prometheus_password == null ? random_password.prometheus_password.result : var.prometheus_password + prometheus_config = { + "basic_auth_users" : { + "admin" : bcrypt(local.prometheus_password) + } + } + prometheus_ssl_config = { + "tls_server_config" : { + "cert_file" : "/etc/certificate.pem", + "key_file" : "/etc/private_key.pem" + } + } + sql_exporter_config = { + "global" : { + "scrape_timeout_offset" : "500ms", + "min_interval" : "0s", + "max_connections" : 3, + "max_idle_connections" : 3 + }, + "target" : { + "data_source_name" : "postgres://${local.config.crate_username}:${urlencode(local.cratedb_password)}@${aws_lb.loadbalancer.dns_name}:5432/crate?sslmode=${var.crate.ssl_enable ? "require" : "disable"}", + "collectors" : ["cratedb_standard"] + }, + "collector_files" : ["*.collector.yml"] + } } resource "random_password" "prometheus_password" { @@ -20,14 +44,16 @@ data "cloudinit_config" "config_utilities" { content_type = "text/cloud-config" content = templatefile("${path.module}/scripts/cloud-init-utilities.tftpl", { - crate_host : aws_lb.loadbalancer.dns_name, - crate_user : local.config.crate_username, - crate_password : local.cratedb_password - prometheus_password : bcrypt(local.prometheus_password) - jmx_targets : indent(16, yamlencode(formatlist("%s:8080", aws_network_interface.interface[*].private_ip))) - node_exporter_targets : indent(16, yamlencode(formatlist("%s:9100", aws_network_interface.interface[*].private_ip))) - ssl_certificate = base64encode(tls_self_signed_cert.ssl.cert_pem) - ssl_private_key = base64encode(tls_private_key.ssl.private_key_pem) + crate_host = aws_lb.loadbalancer.dns_name + crate_user = local.config.crate_username + crate_password = local.cratedb_password + crate_ssl = var.crate.ssl_enable + prometheus_config = indent(6, yamlencode(var.prometheus_ssl ? merge(local.prometheus_config, local.prometheus_ssl_config) : local.prometheus_config)) + sql_exporter_config = indent(6, yamlencode(local.sql_exporter_config)) + jmx_targets = indent(16, yamlencode(formatlist("%s:8080", aws_network_interface.interface[*].private_ip))) + node_exporter_targets = indent(16, yamlencode(formatlist("%s:9100", aws_network_interface.interface[*].private_ip))) + ssl_certificate = base64encode(tls_self_signed_cert.ssl.cert_pem) + ssl_private_key = base64encode(tls_private_key.ssl.private_key_pem) } ) } @@ -57,6 +83,15 @@ resource "aws_security_group" "utilities" { ipv6_cidr_blocks = ["::/0"] } + ingress { + description = "Locust" + from_port = 8089 + to_port = 8089 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + egress { from_port = 0 to_port = 0 diff --git a/aws/main.tf b/aws/main.tf index 905b27b..6aae6a6 100644 --- a/aws/main.tf +++ b/aws/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "aws" - version = "~> 5.7" + version = "~> 5.31" } cloudinit = { @@ -14,7 +14,7 @@ terraform { random = { source = "random" - version = "~> 3.4" + version = "~> 3.6" } tls = { diff --git a/aws/scripts/cloud-init-cratedb-rpm.tftpl b/aws/scripts/cloud-init-cratedb-rpm.tftpl index 605d975..bd68bf0 100644 --- a/aws/scripts/cloud-init-cratedb-rpm.tftpl +++ b/aws/scripts/cloud-init-cratedb-rpm.tftpl @@ -6,7 +6,7 @@ package_reboot_if_required: true yum_repos: prometheus-rpm: - baseurl: https://packagecloud.io/prometheus-rpm/release/el/8/$basearch + baseurl: https://packagecloud.io/prometheus-rpm/release/el/9/$basearch enabled: true gpgcheck: false gpgkey: https://packagecloud.io/prometheus-rpm/release/gpgkey @@ -23,6 +23,7 @@ packages: - openssl - htop - node_exporter + - jq bootcmd: - test -z "$(blkid /dev/nvme1n1)" && mkfs -t xfs -L data /dev/nvme1n1 @@ -42,13 +43,9 @@ write_files: path: /etc/crate/certificate.pem permissions: "0660" - content: | - #!/bin/bash - - sleep 30 - curl -sS -H 'Content-Type: application/json' -k -X POST 'http${crate_ssl_enable ? "s" : ""}://localhost:4200/_sql' -d '{"stmt":"CREATE USER ${crate_user} WITH (password = '\''${crate_pass}'\'');"}' - curl -sS -H 'Content-Type: application/json' -k -X POST 'http${crate_ssl_enable ? "s" : ""}://localhost:4200/_sql' -d '{"stmt":"GRANT ALL PRIVILEGES TO ${crate_user};"}' + ${user_provisioning_file} owner: root:root - path: /opt/deployment/finish.sh + path: /opt/deployment/user_provisioning.sh permissions: "0755" - content: | path.data: /opt/data @@ -112,7 +109,7 @@ runcmd: - curl --output-dir /opt/crate -O https://repo1.maven.org/maven2/io/crate/crate-jmx-exporter/1.0.0/crate-jmx-exporter-1.0.0.jar - systemctl enable crate - systemctl start crate - - bash /opt/deployment/finish.sh && rm -f /opt/deployment/finish.sh + - bash /opt/deployment/user_provisioning.sh "${crate_protocol}" "${crate_user}" "${crate_pass}" && rm -f /opt/deployment/user_provisioning.sh - systemctl enable node_exporter.service - systemctl start node_exporter.service diff --git a/aws/scripts/cloud-init-cratedb-tar.tftpl b/aws/scripts/cloud-init-cratedb-tar.tftpl index ab7753e..65004de 100644 --- a/aws/scripts/cloud-init-cratedb-tar.tftpl +++ b/aws/scripts/cloud-init-cratedb-tar.tftpl @@ -6,7 +6,7 @@ package_reboot_if_required: true yum_repos: prometheus-rpm: - baseurl: https://packagecloud.io/prometheus-rpm/release/el/8/$basearch + baseurl: https://packagecloud.io/prometheus-rpm/release/el/9/$basearch enabled: true gpgcheck: false gpgkey: https://packagecloud.io/prometheus-rpm/release/gpgkey @@ -35,13 +35,9 @@ write_files: path: /opt/crate/config/certificate.pem permissions: "0660" - content: | - #!/bin/bash - - sleep 30 - curl -sS -H 'Content-Type: application/json' -k -X POST 'http${crate_ssl_enable ? "s" : ""}://localhost:4200/_sql' -d '{"stmt":"CREATE USER ${crate_user} WITH (password = '\''${crate_pass}'\'');"}' - curl -sS -H 'Content-Type: application/json' -k -X POST 'http${crate_ssl_enable ? "s" : ""}://localhost:4200/_sql' -d '{"stmt":"GRANT ALL PRIVILEGES TO ${crate_user};"}' + ${user_provisioning_file} owner: root:root - path: /opt/deployment/finish.sh + path: /opt/deployment/user_provisioning.sh permissions: "0755" - content: | path.data: /opt/data @@ -178,7 +174,7 @@ runcmd: - systemctl daemon-reload - systemctl enable crate - systemctl start crate - - bash /opt/deployment/finish.sh && rm -f /opt/deployment/finish.sh + - bash /opt/deployment/user_provisioning.sh "${crate_protocol}" "${crate_user}" "${crate_pass}" && rm -f /opt/deployment/user_provisioning.sh - systemctl enable node_exporter.service - systemctl start node_exporter.service diff --git a/aws/scripts/cloud-init-utilities.tftpl b/aws/scripts/cloud-init-utilities.tftpl index 978364e..c1df9fc 100644 --- a/aws/scripts/cloud-init-utilities.tftpl +++ b/aws/scripts/cloud-init-utilities.tftpl @@ -16,6 +16,8 @@ packages: - git - tmux - htop + - nano + - python3-pip write_files: - content: | @@ -28,7 +30,7 @@ write_files: done sudo -i -u ec2-user bash << EOF - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install node --latest-npm @@ -37,6 +39,8 @@ write_files: cd ~/nodeIngestBench npm install + + pip3 install locust EOF owner: root:root path: /root/node.sh @@ -45,7 +49,7 @@ write_files: CRATE_USER="${crate_user}" CRATE_HOST="${crate_host}" CRATE_PASSWORD="${crate_password}" - CRATE_SSL="true" + CRATE_SSL="${crate_ssl ? "true" : "false"}" path: /root/.env - content: !!binary | ${ssl_private_key} @@ -77,18 +81,7 @@ write_files: - "localhost:9399" path: /etc/prometheus/prometheus.yml - content: | - global: - scrape_timeout_offset: 500ms - min_interval: 0s - max_connections: 3 - max_idle_connections: 3 - - target: - data_source_name: 'postgres://${crate_user}:${urlencode(crate_password)}@${crate_host}:5432/crate?ssl_mode=require' - collectors: [cratedb_standard] - - collector_files: - - "*.collector.yml" + ${sql_exporter_config} path: /etc/prometheus/sql_exporter.yml - content: | collector_name: cratedb_standard @@ -105,12 +98,7 @@ write_files: GROUP BY 1; path: /etc/prometheus/cratedb_standard.collector.yml - content: | - tls_server_config: - cert_file: /etc/certificate.pem - key_file: /etc/private_key.pem - - basic_auth_users: - admin: ${prometheus_password} + ${prometheus_config} path: /etc/prometheus/web.yml - content: | basic_auth_users: diff --git a/aws/scripts/user_provisioning.sh b/aws/scripts/user_provisioning.sh new file mode 100755 index 0000000..954f0a7 --- /dev/null +++ b/aws/scripts/user_provisioning.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +protocol="${1}" +username="${2}" +password="${3}" + +send_sql() { + curl -sS -H 'Content-Type: application/json' -k -X POST "${protocol}://localhost:4200/_sql" -d "$1" +} + +generate_body() { + jq -n --arg stmt "$1" '{"stmt": $stmt}' +} + +sleep 30 + +send_sql "$(generate_body "CREATE USER ${username} WITH (password = \$\$${password}\$\$)")" +send_sql "$(generate_body "GRANT ALL PRIVILEGES TO ${username}")" diff --git a/aws/tests/variables.tftest.hcl b/aws/tests/variables.tftest.hcl new file mode 100644 index 0000000..316f459 --- /dev/null +++ b/aws/tests/variables.tftest.hcl @@ -0,0 +1,58 @@ +variables { + vpc_id = "vpc-123" + ssh_keypair = "test_keypair" + subnet_ids = ["subnet-1"] + availability_zones = ["az-1"] +} + +run "no CrateDB download URL" { + command = plan + + variables { + cratedb_tar_download_url = null + } +} + +run "valid CrateDB download URL" { + command = plan + + variables { + cratedb_tar_download_url = "https://cdn.crate.io/downloads/releases/cratedb/aarch64_linux/crate-5.5.1.tar.gz" + } +} + +run "invalid CrateDB download URL" { + command = plan + + variables { + cratedb_tar_download_url = "https://something_else.com/downloads/releases/cratedb/aarch64_linux/crate-5.5.1.tar.gz" + } + + expect_failures = [var.cratedb_tar_download_url] +} + +run "no CrateDB password" { + command = plan + + variables { + cratedb_password = null + } +} + +run "valid CrateDB password" { + command = plan + + variables { + cratedb_password = "zie6aeya9ooMeey0yai5" + } +} + +run "password with double dollar signs" { + command = plan + + variables { + cratedb_password = "ab$$cd" + } + + expect_failures = [var.cratedb_password] +} diff --git a/aws/variables.tf b/aws/variables.tf index a19c91a..615a669 100644 --- a/aws/variables.tf +++ b/aws/variables.tf @@ -39,6 +39,10 @@ variable "cratedb_password" { default = null sensitive = true description = "The password to use for the CrateDB database user. If null, a random password will be assigned." + validation { + condition = var.cratedb_password == null || !can(regex("\"|\\$\\$", var.cratedb_password)) + error_message = "The CrateDB password must not contain any of the following character sequences: $$, \"" + } } variable "cratedb_tar_download_url" { @@ -163,3 +167,9 @@ variable "prometheus_password" { sensitive = true description = "Optional password for the Prometheus admin user. If null, a random password will be assigned." } + +variable "prometheus_ssl" { + type = bool + default = true + description = "If true, a self-signed SSL certificate will be generated for accessing Prometheus." +}