diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fef4ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# .tfvars files +*.tfvars diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..15bc72f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7331710 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# Terraform Module to create Azure Web App Containers + +Create Web App for Containers (Azure App Service). + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "centralus" +} + +module "web_app_container" { + # Example source URL points to Terraform Enterprise Private Module Registry + + source = "app.terraform.io/multicloud/web-app-container/azurerm" + version = "1.5.0" + + name = "hello-world" + + resource_group_name = "${azurerm_resource_group.example.name}" + + container_type = "docker" + + container_image = "robpco/palacearcade:latest" +} +``` + +## Required Inputs + +| Name | Type | Description | +| --- | --- | --- | +| `name` | `string` | The name of the web app. | +| `resource_group_name` | `string` | The name of an existing resource group to use for the web app. | +| `container_image` | `string` | Container image name. Example: `robpco/palacearcade:latest`. | + +## Optional Inputs + +| Name | Type | Description | +| --- | --- | --- | +| `container_type` | `string` | Type of container. The options are: `docker`, `compose` and `kube`. Default: `docker`. | +| `container_config` | `string` | Configuration for the container. This should be YAML. | +| `port` | `string` | The value of the expected container port number. | +| `enable_storage` | `bool` | Mount an SMB share to the `/home/` directory. Default: `false`. | +| `start_time_limit` | `string` | Configure the amount of time (in seconds) the app service will wait before it restarts the container. Default: `230`. | +| `command` | `string` | A command to be run on the container. | +| `app_settings` | `map` | Set web app settings. These are avilable as environment variables at runtime. | +| `app_service_plan_id` | `string` | The ID of an existing app service plan to use for the web app. | +| `sku_tier` | `string` | The pricing tier of an app service plan to use for the web app. Default: `Standard`. | +| `sku_size` | `string` | The instance size of an app service plan to use for the web app. Default: `S1`. | +| `always_on` | `bool` | Either `true` to ensure the web app gets loaded all the time, or `false` to to unload after being idle. | +| `https_only` | `bool` | Redirect all traffic made to the web app using HTTP to HTTPS. Default: `true`. | +| `ftps_state` | `string` | Set the FTPS state value the web app. The options are: `AllAllowed`, `Disabled` and `FtpsOnly`. Default: `Disabled`. | +| `ip_restrictions` | `list` | Configure IP restrictions for the web app. | +| `custom_hostnames` | `list` | List of custom hostnames to use for the web app. | +| `docker_registry_username` | `string` | The container registry username. | +| `docker_registry_url` | `string` | The container registry url. Default: `https://index.docker.io` | +| `docker_registry_password` | `string` | The container registry password. | +| `tags` | `map` | A mapping of tags to assign to the web app. | diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..10a6c10 --- /dev/null +++ b/main.tf @@ -0,0 +1,67 @@ +locals { + app_service_plan_id = "${var.app_service_plan_id != "" ? var.app_service_plan_id : element(coalescelist(azurerm_app_service_plan.main.*.id, list("")), 0)}" + + container_type = "${upper(var.container_type)}" + container_config = "${base64encode(var.container_config)}" + + app_settings = { + "WEBSITES_CONTAINER_START_TIME_LIMIT" = "${var.start_time_limit}" + "WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "${var.enable_storage}" + "WEBSITES_PORT" = "${var.port}" + "DOCKER_REGISTRY_SERVER_USERNAME" = "${var.docker_registry_username}" + "DOCKER_REGISTRY_SERVER_URL" = "${var.docker_registry_url}" + "DOCKER_REGISTRY_SERVER_PASSWORD" = "${var.docker_registry_password}" + } +} + +data "azurerm_resource_group" "main" { + name = "${var.resource_group_name}" +} + +resource "azurerm_app_service_plan" "main" { + count = "${var.app_service_plan_id == "" ? 1 : 0}" + name = "${var.name}-plan" + location = "${data.azurerm_resource_group.main.location}" + resource_group_name = "${data.azurerm_resource_group.main.name}" + kind = "linux" + reserved = true + + sku { + tier = "${var.sku_tier}" + size = "${var.sku_size}" + } + + tags = "${var.tags}" +} + +resource "azurerm_app_service" "main" { + name = "${var.name}" + location = "${data.azurerm_resource_group.main.location}" + resource_group_name = "${data.azurerm_resource_group.main.name}" + app_service_plan_id = "${local.app_service_plan_id}" + + https_only = "${var.https_only}" + + site_config { + always_on = "${var.always_on}" + app_command_line = "${var.command}" + ftps_state = "${var.ftps_state}" + ip_restriction = "${var.ip_restrictions}" + linux_fx_version = "${local.container_type}|${local.container_type == "DOCKER" ? var.container_image : local.container_config}" + } + + app_settings = "${merge(var.app_settings, local.app_settings)}" + + identity { + type = "SystemAssigned" + } + + tags = "${var.tags}" +} + +resource "azurerm_app_service_custom_hostname_binding" "main" { + count = "${length(var.custom_hostnames)}" + hostname = "${var.custom_hostnames[count.index]}" + app_service_name = "${azurerm_app_service.main.name}" + resource_group_name = "${data.azurerm_resource_group.main.name}" +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..fdc0bc8 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,28 @@ +output "id" { + value = "${azurerm_app_service.main.id}" + + description = "The ID of the App Service." +} + +output "hostname" { + value = "${azurerm_app_service.main.default_site_hostname}" + + description = "The default hostname for the App Service." +} + +output "outbound_ips" { + value = "${split(",", azurerm_app_service.main.outbound_ip_addresses)}" + + description = "A list of outbound IP addresses for the App Service." +} + +output "possible_outbound_ips" { + value = "${split(",", azurerm_app_service.main.possible_outbound_ip_addresses)}" + + description = "A list of possible outbound IP addresses for the App Service. Superset of outbound_ips." +} + +output "principal_id" { + value = "${azurerm_app_service.main.identity.0.principal_id}" + description = "The principal ID for the system-assigned identity associated with the App Service." +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..dcc48fa --- /dev/null +++ b/variables.tf @@ -0,0 +1,171 @@ +variable "name" { + type = "string" + + description = "The name of the web app." +} + +variable "resource_group_name" { + type = "string" + + description = "The name of an existing resource group to use for the web app." +} + +variable "container_type" { + type = "string" + + default = "docker" + + description = "Type of container. The options are: `docker`, `compose` or `kube`." +} + +variable "container_config" { + type = "string" + + default = "" + + description = "Configuration for the container. This should be YAML." +} + +variable "container_image" { + type = "string" + + default = "" + + description = "Container image name. Example: `innovationnorway/python-hello-world:latest`." +} + +variable "port" { + type = "string" + + default = "" + + description = "The value of the expected container port number." +} + +variable "enable_storage" { + type = "string" + + default = "false" + + description = "Mount an SMB share to the `/home/` directory." +} + +variable "start_time_limit" { + type = "string" + + default = "230" + + description = "Configure the amount of time (in seconds) the app service will wait before it restarts the container." +} + +variable "command" { + type = "string" + + default = "" + + description = "A command to be run on the container." +} + +variable "app_settings" { + type = "map" + + default = {} + + description = "Set web app settings. These are avilable as environment variables at runtime." +} + +variable "app_service_plan_id" { + type = "string" + + default = "" + + description = "The ID of an existing app service plan to use for the web app." +} + +variable "sku_tier" { + type = "string" + + default = "Standard" + + description = "The pricing tier of an app service plan to use for the web app." +} + +variable "sku_size" { + type = "string" + + default = "S1" + + description = "The instance size of an app service plan to use for the web app." +} + +variable "always_on" { + type = "string" + + default = true + + description = "Either `true` to ensure the web app gets loaded all the time, or `false` to to unload after being idle." +} + +variable "https_only" { + type = "string" + + default = true + + description = "Redirect all traffic made to the web app using HTTP to HTTPS." +} + +variable "ftps_state" { + type = "string" + + default = "Disabled" + + description = "Set the FTPS state value the web app. The options are: `AllAllowed`, `Disabled` and `FtpsOnly`." +} + +variable "ip_restrictions" { + type = "list" + + default = [] + + description = "Configure IP restrictions for the web app." +} + +variable "custom_hostnames" { + type = "list" + + default = [] + + description = "List of custom hostnames to use for the web app." +} + +variable "docker_registry_username" { + type = "string" + + default = "" + + description = "The container registry username." +} + +variable "docker_registry_url" { + type = "string" + + default = "https://index.docker.io" + + description = "The container registry url." +} + +variable "docker_registry_password" { + type = "string" + + default = "" + + description = "The container registry password." +} + +variable "tags" { + type = "map" + + default = {} + + description = "A mapping of tags to assign to the web app." +}