├── .gitignore ├── azurerm_client_config.tf ├── terraform.tfvars.example ├── azurerm.tf ├── terraform.tf ├── azurerm_resource_group.tf ├── azurerm_storage_container.tf ├── outputs.tf ├── azurerm_storage_account.tf ├── azurerm_virtual_network.tf ├── azurerm_redis_enterprise_database.tf ├── azurerm_subnet.tf ├── azurerm_redis_enterprise_cluster.tf ├── azurerm_private_endpoint.tf ├── variables.tf ├── LICENSE ├── random_string.tf └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .envrc 3 | .terraform* 4 | terraform.tfstate* 5 | -------------------------------------------------------------------------------- /azurerm_client_config.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_client_config" "current" { 2 | } -------------------------------------------------------------------------------- /terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | subscription_id = 2 | tenant_id = 3 | client_id = 4 | client_secret = 5 | -------------------------------------------------------------------------------- /azurerm.tf: -------------------------------------------------------------------------------- 1 | provider "azurerm" { 2 | environment = var.cloud_name 3 | features { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = ">= 2.67.0" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /azurerm_resource_group.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_resource_group" "redisgeek" { 2 | name = format("redisgeek-%s", random_string.resource_group_name.result) 3 | location = var.location 4 | tags = merge(var.tags, { owner = data.azurerm_client_config.current.client_id }) 5 | } 6 | -------------------------------------------------------------------------------- /azurerm_storage_container.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_storage_container" "redisgeek" { 2 | name = format("%s%s", random_string.storage_account_name.result, random_string.storage_container_name.result) 3 | storage_account_name = azurerm_storage_account.redisgeek.name 4 | container_access_type = "private" 5 | } 6 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | redisgeek_config = { 3 | hostname = azurerm_redis_enterprise_cluster.redisgeek.hostname 4 | access_key = azurerm_redis_enterprise_database.redisgeek.primary_access_key 5 | port = "10000" 6 | } 7 | } 8 | 9 | output "redisgeek_config" { 10 | value = local.redisgeek_config 11 | sensitive = true 12 | } 13 | -------------------------------------------------------------------------------- /azurerm_storage_account.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_storage_account" "redisgeek" { 2 | name = format("redisgeek%s", random_string.storage_account_name.result) 3 | resource_group_name = azurerm_resource_group.redisgeek.name 4 | location = azurerm_resource_group.redisgeek.location 5 | account_tier = "Standard" 6 | account_replication_type = "LRS" 7 | } 8 | -------------------------------------------------------------------------------- /azurerm_virtual_network.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_virtual_network" "redisgeek" { 2 | name = format("redisgeek-%s", random_string.vnet_name.result) 3 | depends_on = [azurerm_resource_group.redisgeek] 4 | resource_group_name = azurerm_resource_group.redisgeek.name 5 | address_space = ["10.0.0.0/16"] 6 | location = azurerm_resource_group.redisgeek.location 7 | } 8 | -------------------------------------------------------------------------------- /azurerm_redis_enterprise_database.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_redis_enterprise_database" "redisgeek" { 2 | name = "default" 3 | resource_group_name = azurerm_resource_group.redisgeek.name 4 | cluster_id = azurerm_redis_enterprise_cluster.redisgeek.id 5 | clustering_policy = var.azure_redis_enterprise_database_clustering_policy 6 | module { 7 | name = "RediSearch" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /azurerm_subnet.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_subnet" "subnet" { 2 | address_prefixes = ["10.0.1.0/24"] 3 | enforce_private_link_endpoint_network_policies = true 4 | name = format("redisgeek-%s", random_string.subnet_name.result) 5 | resource_group_name = azurerm_resource_group.redisgeek.name 6 | virtual_network_name = azurerm_virtual_network.redisgeek.name 7 | } 8 | -------------------------------------------------------------------------------- /azurerm_redis_enterprise_cluster.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_redis_enterprise_cluster" "redisgeek" { 2 | name = format("redisgeek-%s", random_string.redis_enterprise_name.result) 3 | resource_group_name = azurerm_resource_group.redisgeek.name 4 | location = azurerm_resource_group.redisgeek.location 5 | zones = [1, 2, 3] 6 | sku_name = var.acre_sku 7 | tags = merge(var.tags, { owner = data.azurerm_client_config.current.client_id }) 8 | } 9 | -------------------------------------------------------------------------------- /azurerm_private_endpoint.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_private_endpoint" "acre" { 2 | name = format("redisgeek-%s", random_string.private_link_name.result) 3 | location = azurerm_resource_group.redisgeek.location 4 | resource_group_name = azurerm_resource_group.redisgeek.name 5 | subnet_id = azurerm_subnet.subnet.id 6 | 7 | private_service_connection { 8 | name = format("redisgeek-sc-%s", random_string.private_link_name.result) 9 | private_connection_resource_id = azurerm_redis_enterprise_cluster.redisgeek.id 10 | is_manual_connection = false 11 | subresource_names = ["redisEnterprise"] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "acre_sku" { 2 | type = string 3 | default = "Enterprise_E10-2" 4 | } 5 | 6 | variable "azure_redis_enterprise_database_clustering_policy" { 7 | type = string 8 | default = "EnterpriseCluster" 9 | } 10 | 11 | variable "location" { 12 | type = string 13 | default = "East US" 14 | } 15 | 16 | variable "cloud_name" { 17 | description = "The Azure cloud environment to use. Available values at https://www.terraform.io/docs/providers/azurerm/#environment" 18 | default = "public" 19 | type = string 20 | } 21 | 22 | variable "tags" { 23 | description = "Key/value tags to assign to all resources." 24 | default = {} 25 | type = map(string) 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 redisgeek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /random_string.tf: -------------------------------------------------------------------------------- 1 | resource "random_string" "redis_enterprise_name" { 2 | length = 4 3 | special = false 4 | upper = false 5 | } 6 | 7 | resource "random_string" "resource_group_name" { 8 | length = 4 9 | special = false 10 | } 11 | 12 | resource "random_string" "storage_account_name" { 13 | length = 4 14 | number = false 15 | special = false 16 | upper = false 17 | } 18 | 19 | resource "random_string" "storage_container_name" { 20 | length = 4 21 | number = false 22 | special = false 23 | upper = false 24 | } 25 | 26 | resource "random_string" "vnet_name" { 27 | length = 4 28 | special = false 29 | upper = false 30 | } 31 | 32 | resource "random_string" "subnet_name" { 33 | length = 4 34 | special = false 35 | upper = false 36 | } 37 | 38 | resource "random_string" "nic_name" { 39 | length = 4 40 | special = false 41 | upper = false 42 | } 43 | 44 | resource "random_string" "vm_name" { 45 | length = 4 46 | special = false 47 | upper = false 48 | } 49 | 50 | resource "random_string" "acre_name" { 51 | length = 4 52 | special = false 53 | upper = false 54 | } 55 | 56 | resource "random_string" "private_link_name" { 57 | length = 4 58 | special = false 59 | upper = false 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Contributors][contributors-shield]][contributors-url] 2 | [![Forks][forks-shield]][forks-url] 3 | [![Stargazers][stars-shield]][stars-url] 4 | [![Issues][issues-shield]][issues-url] 5 | [![MIT License][license-shield]][license-url] 6 | 7 | # ACRE-TERRAFORM 8 | 9 | This is a template to get started with the 'azurerm_redis_enterprise_cluster' resource 10 | available in the 'azurerm' provider with Terraform. 11 | 12 | - _Tenant_ 13 | - _Subscription_ 14 | - **Resource Group** 15 | - **Storage Account** 16 | - **Storage Container** 17 | - **VNET** 18 | - **Subnet** 19 | - **Redis Enterprise Cluster** 20 | - **Private Link connecting subnet and cluster** 21 | 22 | The RediSearch module will be included. 23 | A private link, vnet and subnet connect to the instance. 24 | The public endpoint will be disabled. 25 | 26 | ## [Getting Started](#getting-started) | [About](#about-the-project) | [License](#license) 27 | 28 | ## Getting Started 29 | 30 | ### Prerequisites 31 | 32 | 1. [Terraform](https://terraform.io]) [CLI](https://terraform.io/downloads.html) 33 | 2. [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) 34 | 35 | ### Step 1. Getting Started 36 | 37 | Login to Azure using the Azure CLI 38 | 39 | ```bash 40 | az login 41 | ``` 42 | >Login with a Service Principal will also work 43 | 44 | Login using an Azure Service Principal 45 | 46 | ```bash 47 | az login --service-principal --username APP_ID --tenant TENANT_ID --password [password || /path/to/cert] 48 | ``` 49 | 50 | ### Step 2: Clone the repository 51 | 52 | ```bash 53 | git clone https://github.com/redis-developer/acre-terraform 54 | ``` 55 | 56 | ### Step 3: Initialize the repository 57 | 58 | ```bash 59 | cd acre-terraform 60 | terraform init 61 | ``` 62 | >The output should include: ```Terraform has been successfully initialized``` 63 | 64 | ### Step 4: Optionally, modify the variables 65 | 66 | The default variables deploy the smallest 'E10' instance into the 'East US' region. 67 | Changes can be made by updating the ```variables.tf``` file. 68 | 69 | 70 | ### Step 5: Verify the plan 71 | 72 | The 'plan' output will show you everything being created by the template. 73 | 74 | ```bash 75 | terraform plan 76 | ``` 77 | >The plan step does not make any changes in Azure 78 | 79 | 80 | ### Step 6: Apply the plan 81 | 82 | When the plan looks good, 'apply' the template. 83 | 84 | ```bash 85 | terraform apply 86 | ``` 87 | 88 | ### Step 7: Connect using generated output 89 | 90 | Connecting to this instance will have to be done from within the subnet that was created. 91 | Only clients within the subnet can access the instance via the private link. 92 | The access key is sensitive, so viewing the outputs must be requested specifically. 93 | 94 | ```bash 95 | terraform output redisgeek_config 96 | ``` 97 | > Example output: 98 | ``` 99 | { 100 | "hostname" = "redis-developer-8jy4.eastus.redisenterprise.cache.azure.net" 101 | "access_key" = "DQYABC3uRMyDguE1236Xkvv3TprUcqBWTRkfgOPjs82Y=" 102 | "port" = "10000" 103 | } 104 | ``` 105 | 106 | ### Step 8: Optionally, Cleanup 107 | 108 | Remove the resources that were created. 109 | 110 | ```bash 111 | terraform destroy 112 | ``` 113 | 114 | ## About The Project 115 | 116 | The cluster, deployed across 3-AZs, will have a 99.99 SLA that is financially backed by Azure. 117 | There are no "preview" features or modules included in this template. 118 | Deployment using a private endpoint is typical for production workloads. 119 | The storage account and storage container are there for exporting/importing RDB files. 120 | 121 | ### See Also 122 | 123 | * [ACRE-TERRAFORM-SIMPLE](https://github.com/redis-developer/acre-terraform) 124 | * [Redis Developer](https://developer.redislabs.com/create/azure/) 125 | 126 | ### Built With 127 | 128 | * [Terraform](https://terraform.io) 129 | 130 | ### Contributing 131 | 132 | Pull-requests are welcomed! 133 | 134 | ## License 135 | 136 | Distributed under the MIT License. See `LICENSE` for more information. 137 | 138 | [contributors-shield]: https://img.shields.io/github/contributors/redis-developer/acre-terraform.svg?style=for-the-badge 139 | [contributors-url]: https://github.com/redis-developer/acre-terraform/graphs/contributors 140 | [forks-shield]: https://img.shields.io/github/forks/redis-developer/acre-terraform.svg?style=for-the-badge 141 | [forks-url]: https://github.com/redis-developer/acre-terraform/network/members 142 | [stars-shield]: https://img.shields.io/github/stars/redis-developer/acre-terraform.svg?style=for-the-badge 143 | [stars-url]: https://github.com/redis-developer/acre-terraform/stargazers 144 | [issues-shield]: https://img.shields.io/github/issues/redis-developer/acre-terraform.svg?style=for-the-badge 145 | [issues-url]: https://github.com/redis-developer/acre-terraform/issues 146 | [license-shield]: https://img.shields.io/github/license/redis-developer/acre-terraform.svg?style=for-the-badge 147 | [license-url]: https://github.com/redis-developer/acre-terraform/blob/main/LICENSE --------------------------------------------------------------------------------