Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GDB-10856] Added External AGW and context path support #91

Closed
wants to merge 12 commits into from
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ terraform.rc
*.pem
*.p12
*.pub
*.pfx
*.crt

#Licenses
*.license

#Private key
*.key
26 changes: 14 additions & 12 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# GraphDB Azure Terraform Module Changelog
## 1.4.0

* Introduced support for deployment with an external Application Gateway.
* Added an option to configure the context path.

## 1.3.4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These updates should not be here if you rebased properly, also you need to update the Changelog with your changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still valid

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still valid.
Also you need to add a new version with your changes to the CHANGELOG.md


Expand Down
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ az vm image terms accept --offer graphdb-ee --plan graphdb-byol --publisher onto
| gateway\_global\_request\_buffering\_enabled | Whether Application Gateway's Request buffer is enabled. | `bool` | `true` | no |
| gateway\_global\_response\_buffering\_enabled | Whether Application Gateway's Response buffer is enabled. | `bool` | `true` | no |
| gateway\_enable\_private\_access | Enable or disable private access to the application gateway | `bool` | `false` | no |
| disable\_agw | Disables the creation of Application Gateway by the Terraform module. | `bool` | `false` | no |
| gateway\_enable\_private\_link\_service | Set to true to enable Private Link service, false to disable it. | `bool` | `false` | no |
| gateway\_private\_link\_service\_network\_policies\_enabled | Enable or disable private link service network policies | `string` | `false` | no |
| gateway\_backend\_port | Backend port for the Application Gateway rules | `number` | `7201` | no |
| gateway\_probe\_interval | Interval in seconds between the health probe checks | `number` | `10` | no |
| gateway\_probe\_timeout | Timeout in seconds for the health probe checks | `number` | `1` | no |
| gateway\_probe\_threshold | Number of consecutive health checks to consider the probe passing or failing | `number` | `2` | no |
| context\_path | The context path for the Application Gateway. | `string` | `""` | no |
| tls\_certificate\_path | Path to a TLS certificate that will be imported in Azure Key Vault and used in the Application Gateway TLS listener for GraphDB. Either tls\_certificate\_path or tls\_certificate\_id must be provided. | `string` | `null` | no |
| tls\_certificate\_password | TLS certificate password for password-protected certificates. | `string` | `null` | no |
| tls\_certificate\_id | Resource identifier for a TLS certificate secret from a Key Vault. Overrides tls\_certificate\_path. Either tls\_certificate\_id or tls\_certificate\_path must be provided. | `string` | `null` | no |
Expand Down Expand Up @@ -368,6 +370,45 @@ To deploy in already existing Resource Group and Virtual Network you just need t
resource_group_name = "existing_rg"
virtual_network_name = "existing_vnet"
```
**Deploying GraphDB with External Application Gateway and Custom Context Path**

You can deploy GraphDB without creating a new Application Gateway, allowing you to use your existing one. Additionally, you can configure a custom context path for your application. To do this, follow these steps:

**_Prerequisites_**:
- *Resource Group*: A resource group should already be created.
- *Virtual Network*: A Virtual Network (VNet) should be set up and ready.
- *Application Gateway*: Ensure your Application Gateway is deployed and fully operational.

_Example Configuration:_
```hcl
context_path = "/graphdb"
disable_agw = true
virtual_network_name = "your-VNet"
resource_group_name = "your-resource-group"
graphdb_external_address_fqdn = "your-fqdn-or-ip"
```

_Notes_:
- Setting `disable_agw` to true allows you to use your existing Application Gateway.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reword this, Setting disable_agw to true will disable ....

- When using `disable_agw` you need to set `graphdb_external_adress_fqdn` as well.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using disable_agw .... > You need to provide graphdb_external_adress_fqdn when disable_agw is set to true

- The `context_path` variable sets the custom context path for your application.

**_Post-Deployment Actions_**:
After applying the Terraform code, you must perform the following steps:

**1.** Configure the Application Gateway:
- Path-Based Routing Rule: Set up a path-based routing rule on your Application Gateway to listen to the same context path. For example, if `context_path = "/graphdb"`, the path-based rule should be `/graphdb/*`.

_Note_:
- You can use your External Application Gateway without the context path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External should be with lower case


**2.** Add VMs or VMSS to Backend Pool:
- Manually add your Virtual Machine Scale Sets (VMSS) to the Application Gateway’s backend pool as targets.

**3.** Upgrade VM Instances:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrade VMSS Instances

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This not is still valid

- After assigning the VMSS to the backend pool and verifying that the Application Gateway can access the VMSS, upgrade your VM instances to the latest model or version. This is essential for the Application Gateway to identify them as valid targets within the backend pool.
**4.** Network Security Group (NSG) Configuration:
- Configure NSG rules to allow traffic between the Application Gateway and the VMSS, ensuring the necessary access is in place.

## Local Development

Expand All @@ -391,8 +432,6 @@ Here is the procedure for migrating your single node deployment to cluster e.g.,
4. Validate the import is successful by checking the `terraform.tfstate` file, should contain `azurerm_managed_disk`
resource with the name of the disk you've imported.
5. Run `terraform plan` and review the plan carefully if everything seems fine run `terraform apply`


## Release History

All notable changes between version are tracked and documented at [CHANGELOG.md](CHANGELOG.md).
Expand Down
18 changes: 14 additions & 4 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ module "tls" {
module "application_gateway" {
source = "./modules/gateway"

count = var.disable_agw ? 0 : 1

resource_name_prefix = var.resource_name_prefix
location = var.location
resource_group_name = local.resource_group_name
Expand All @@ -179,6 +181,9 @@ module "application_gateway" {
# Public / Private toggle
gateway_enable_private_access = var.gateway_enable_private_access

disable_agw = var.disable_agw
context_path = var.context_path

# TLS
gateway_tls_certificate_secret_id = var.tls_certificate_id != null ? var.tls_certificate_id : module.tls[0].tls_certificate_id
gateway_tls_certificate_identity_id = var.tls_certificate_id != null ? var.tls_certificate_identity_id : module.tls[0].tls_identity_id
Expand Down Expand Up @@ -222,10 +227,11 @@ module "monitoring" {
location = var.location
node_count = var.node_count

web_test_availability_request_url = module.application_gateway.public_ip_address_fqdn
web_test_availability_request_url = var.disable_agw ? var.graphdb_external_address_fqdn : module.application_gateway[0].public_ip_address_fqdn
web_test_geo_locations = var.web_test_geo_locations
web_test_ssl_check_enabled = var.web_test_ssl_check_enabled
graphdb_external_address_fqdn = var.graphdb_external_address_fqdn != null ? var.graphdb_external_address_fqdn : module.application_gateway.public_ip_address_fqdn

graphdb_external_address_fqdn = var.graphdb_external_address_fqdn != null ? var.graphdb_external_address_fqdn : module.application_gateway[0].public_ip_address_fqdn

monitor_reader_principal_id = var.monitor_reader_principal_id

Expand Down Expand Up @@ -270,14 +276,16 @@ module "graphdb" {
graphdb_outbound_address_prefixes = var.outbound_allowed_address_prefixes

# Gateway
application_gateway_backend_address_pool_ids = [module.application_gateway.gateway_backend_address_pool_id]
application_gateway_backend_address_pool_ids = var.disable_agw ? [] : [module.application_gateway[0].gateway_backend_address_pool_id]

context_path = var.context_path

# App Configuration
app_configuration_id = module.appconfig.app_configuration_id
app_configuration_endpoint = module.appconfig.app_configuration_endpoint

# GraphDB Configurations
graphdb_external_address_fqdn = var.graphdb_external_address_fqdn != null ? var.graphdb_external_address_fqdn : module.application_gateway.public_ip_address_fqdn
graphdb_external_address_fqdn = var.graphdb_external_address_fqdn != null ? var.graphdb_external_address_fqdn : (var.disable_agw ? null : module.application_gateway[0].public_ip_address_fqdn)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the graphdb.properties file look like when disable_agw is true?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is still valid

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When disabled_agw is true, I have added new validations (will push soon). It uses the Frontend public IP address of the external Application Gateway. It also adds the context path if there is one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will produce wrong graphdb.properties file when using external Application Gateway and graphdb_external_address_fqdn is not provided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, external fdqn variable is needed. I will add a note that it is required when disabled_agw is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still want to see the outputted graphdb.properties file

graphdb_password = var.graphdb_password
graphdb_license_path = var.graphdb_license_path
graphdb_cluster_token = var.graphdb_cluster_token
Expand Down Expand Up @@ -317,5 +325,7 @@ module "graphdb" {
appi_connection_string = var.deploy_monitoring ? module.monitoring[0].appi_connection_string : ""

# Wait for the configurations to be created in the App Configuration store
disable_agw = var.disable_agw

depends_on = [module.appconfig]
}
52 changes: 44 additions & 8 deletions modules/gateway/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ locals {
gateway_private_link_configuration_name = "${var.resource_name_prefix}-private-link-configuration"
gateway_private_link_ip_configuration_name = "${var.resource_name_prefix}-private-link-ip-configuration"
gateway_frontend_private_ip_configuration_name = "${var.resource_name_prefix}-private-ip"
clean_context_path = trim(var.context_path, "/")
}

# Public Application Gateway
Expand Down Expand Up @@ -147,14 +148,49 @@ resource "azurerm_application_gateway" "graphdb-public" {
redirect_configuration_name = local.gateway_redirect_rule_name
}

# HTTPS request routing rule
request_routing_rule {
name = local.gateway_https_request_routing_rule_name
priority = 10
rule_type = "Basic"
http_listener_name = local.gateway_https_listener_name
backend_address_pool_name = local.gateway_backend_address_pool_name
backend_http_settings_name = local.gateway_backend_http_settings_name
# HTTPS request - Path-Based routing rule
# Conditionally create a request routing rule based on the var.context_path
dynamic "request_routing_rule" {
for_each = var.context_path != null && var.context_path != "" ? [1] : []

content {
name = local.gateway_https_request_routing_rule_name
priority = 10
rule_type = "PathBasedRouting"
http_listener_name = local.gateway_https_listener_name
url_path_map_name = "path-map"
}
}

# HTTPS request Basic routing rule
# Fallback to a Basic Rule when var.context_path is empty
dynamic "request_routing_rule" {
for_each = var.context_path == null || var.context_path == "" ? [1] : []

content {
name = local.gateway_https_request_routing_rule_name
priority = 10
rule_type = "Basic"
http_listener_name = local.gateway_https_listener_name
backend_address_pool_name = local.gateway_backend_address_pool_name
backend_http_settings_name = local.gateway_backend_http_settings_name
}
}
dynamic "url_path_map" {
viktor-ribchev marked this conversation as resolved.
Show resolved Hide resolved
for_each = var.context_path != null && var.context_path != "" ? [1] : []

content {
name = "path-map"
default_backend_address_pool_name = local.gateway_backend_address_pool_name
default_backend_http_settings_name = local.gateway_backend_http_settings_name

path_rule {
name = "context-path-rule"
paths = ["/${local.clean_context_path}/*"]
backend_address_pool_name = local.gateway_backend_address_pool_name
backend_http_settings_name = local.gateway_backend_http_settings_name
}
}
}
}

Expand Down
26 changes: 24 additions & 2 deletions modules/gateway/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,32 @@ output "public_ip_address_fqdn" {

output "gateway_id" {
description = "Identifier of the application gateway for GraphDB"
value = var.gateway_enable_private_access ? azurerm_application_gateway.graphdb-private[0].id : azurerm_application_gateway.graphdb-public[0].id
value = var.gateway_enable_private_access && length(azurerm_application_gateway.graphdb-private) > 0 ? azurerm_application_gateway.graphdb-private[0].id : !var.gateway_enable_private_access && length(azurerm_application_gateway.graphdb-public) > 0 ? azurerm_application_gateway.graphdb-public[0].id : null
}

# Outputs the ID of the Application Gateway's backend address pool.
# - If 'disable_agw' is false and 'gateway_enable_private_access' is true, it retrieves the ID from the private Application Gateway.
# - If 'disable_agw' is false and 'gateway_enable_private_access' is false, it retrieves the ID from the public Application Gateway.
# - If the Application Gateway is disabled or not available, it outputs null.

output "gateway_backend_address_pool_id" {
description = "Identifier of the application gateway backend address pool"
value = var.gateway_enable_private_access ? one(azurerm_application_gateway.graphdb-private[0].backend_address_pool).id : one(azurerm_application_gateway.graphdb-public[0].backend_address_pool).id
value = (
viktor-ribchev marked this conversation as resolved.
Show resolved Hide resolved
!var.disable_agw && var.gateway_enable_private_access
&& length(azurerm_application_gateway.graphdb-private) > 0
? (
length(azurerm_application_gateway.graphdb-private[0].backend_address_pool) > 0
? one(azurerm_application_gateway.graphdb-private[0].backend_address_pool).id
: null
)
: !var.disable_agw && !var.gateway_enable_private_access
&& length(azurerm_application_gateway.graphdb-public) > 0
? (
length(azurerm_application_gateway.graphdb-public[0].backend_address_pool) > 0
? one(azurerm_application_gateway.graphdb-public[0].backend_address_pool).id
: null
)
: null
)
}

10 changes: 10 additions & 0 deletions modules/gateway/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ variable "gateway_enable_private_access" {
type = bool
}

variable "disable_agw" {
description = "Disables the creation of Application Gateway by the Terraform module."
type = bool
}

variable "context_path" {
description = "The context path for the Application Gateway."
type = string
}

variable "gateway_min_capacity" {
description = "Minimum capacity for the Application Gateway autoscaling"
type = number
Expand Down
27 changes: 24 additions & 3 deletions modules/graphdb/templates/04_gdb_conf_overrides.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,23 @@ log_with_timestamp "Writing configuration files"

# graphdb.external-url.enforce.transactions: determines whether it is necessary to rewrite the Location header when no proxy is configured.
# This is required because when working with the GDB transaction endpoint it returns an erroneous URL with HTTP protocol instead of HTTPS
CLEAN_CONTEXT_PATH=$(echo "${context_path}" | sed 's#^/*##' | sed 's#/*$##')

if [ "${node_count}" -eq 1 ]; then

if [ -n "${context_path}" ]; then
EXTERNAL_URL="https://${graphdb_external_address_fqdn}/$${CLEAN_CONTEXT_PATH}"
else
EXTERNAL_URL="https://${graphdb_external_address_fqdn}"
viktor-ribchev marked this conversation as resolved.
Show resolved Hide resolved
fi

cat <<EOF >/etc/graphdb/graphdb.properties
graphdb.connector.port=7200
graphdb.external-url=https://${graphdb_external_address_fqdn}
graphdb.external-url=$${EXTERNAL_URL}
graphdb.external-url.enforce.transactions=true
EOF
else

RECORD_NAME=$(cat /var/opt/graphdb/node_dns_name)

log_with_timestamp "Getting the cluster token"
Expand All @@ -51,18 +61,29 @@ else
log_with_timestamp "Getting the full DNS record for current instance"
NODE_DNS=$(az network private-dns record-set a show --resource-group $RESOURCE_GROUP --zone-name $DNS_ZONE_NAME --name $RECORD_NAME --output tsv --query "fqdn" | rev | cut -c 2- | rev)

if [ -n "${context_path}" ]; then
VHOSTS_VALUE="https://${graphdb_external_address_fqdn}/$${CLEAN_CONTEXT_PATH}/,http://$${NODE_DNS}:7200"
else
VHOSTS_VALUE="https://${graphdb_external_address_fqdn}/,http://$${NODE_DNS}:7200"
fi

cat <<EOF >/etc/graphdb/graphdb.properties
graphdb.auth.token.secret=$graphdb_cluster_token
graphdb.connector.port=7200
graphdb.vhosts=$${VHOSTS_VALUE}
graphdb.external-url=http://$${NODE_DNS}:7200/
graphdb.rpc.address=$${NODE_DNS}:7300
EOF

if [ -n "${context_path}" ]; then
EXTERNAL_URL="https://${graphdb_external_address_fqdn}/$${CLEAN_CONTEXT_PATH}/"
else
EXTERNAL_URL="https://${graphdb_external_address_fqdn}/"
fi
simonzhekoff marked this conversation as resolved.
Show resolved Hide resolved
cat <<EOF >/etc/graphdb-cluster-proxy/graphdb.properties
graphdb.auth.token.secret=$graphdb_cluster_token
graphdb.connector.port=7201
graphdb.external-url=https://${graphdb_external_address_fqdn}
graphdb.vhosts=https://${graphdb_external_address_fqdn},http://$${NODE_DNS}:7201
graphdb.external-url=$${EXTERNAL_URL}
graphdb.rpc.address=$${NODE_DNS}:7301
graphdb.proxy.hosts=$${NODE_DNS}:7300
EOF
Expand Down
2 changes: 2 additions & 0 deletions modules/graphdb/user_data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ data "cloudinit_config" "entrypoint" {
graphdb_password_secret_name : var.graphdb_password_secret_name
graphdb_properties_secret_name : var.graphdb_properties_secret_name
graphdb_java_options_secret_name : var.graphdb_java_options_secret_name
context_path : var.context_path
disable_agw : var.disable_agw
})
}

Expand Down
9 changes: 9 additions & 0 deletions modules/graphdb/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,12 @@ variable "user_supplied_scripts" {
type = list(string)
}

variable "disable_agw" {
description = "Disables the creation of Application Gateway by the Terraform module."
type = bool
}

variable "context_path" {
description = "The context path for the Application Gateway."
type = string
}
Loading