Added recipe for Apigee X with SWP
This commit is contained in:
committed by
Wiktor Niesiobędzki
parent
077d8719dd
commit
a2f4d9185b
3
.gitignore
vendored
3
.gitignore
vendored
@@ -58,3 +58,6 @@ blueprints/gke/autopilot/bundle/monitoring/kustomization.yaml
|
||||
blueprints/gke/autopilot/bundle/locust/kustomization.yaml
|
||||
blueprints/gke/autopilot/bundle.tar.gz
|
||||
blueprints/gke/patterns/batch/job-*.yaml
|
||||
modules/apigee/recipe-apigee-swp/bundle.zip
|
||||
modules/apigee/recipe-apigee-swp/deploy-apiproxy.sh
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ This module simplifies the creation of a Apigee resources (organization, environ
|
||||
- [New endpoint attachment](#new-endpoint-attachment)
|
||||
- [Apigee add-ons](#apigee-add-ons)
|
||||
- [IAM](#iam)
|
||||
- [Recipes](#recipes)
|
||||
- [Variables](#variables)
|
||||
- [Outputs](#outputs)
|
||||
<!-- END TOC -->
|
||||
@@ -355,6 +356,10 @@ module "apigee" {
|
||||
# tftest modules=1 resources=10
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Recipes
|
||||
|
||||
- [Apigee X with Secure Web Proxy](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/blob/master/modules/apigee/recipe-apigee-swp)
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|
||||
57
modules/apigee/recipe-apigee-swp/README.md
Normal file
57
modules/apigee/recipe-apigee-swp/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Apigee X with Secure Web Proxy
|
||||
|
||||
This recipe demonstrates how to configure Apigee X with Secure Web Proxy (SWP). This is a common solution when you need your Apigee X runtime to connect to numerous on-premises backends, but prefer to avoid establishing VPC peering between the Apigee X Google-managed VPC and the VPC where hybrid connectivity and advertising Apigee X runtime IP ranges to the on-premises network.
|
||||
|
||||
The diagram below depicts the architecture deployed:
|
||||
|
||||

|
||||
|
||||
In this recipe the SWP gateway has been co-located with Apigee X in the same project for ease of deployment. It's important to note that the SWP gateway's deployment is flexible and can be independently placed in a different project. Our current setup uses a privately accessible VM as the backend target for SWP. In a real-world scenario, with hybrid connectivity configured in the SWP gateway's VPC, the backend could alternatively be an on-premises host.
|
||||
|
||||
Once the terraform configuration is applied you can verify that all is working by running the following:
|
||||
|
||||
* Deploy a sample proxy to Apigee X
|
||||
|
||||
./deploy-apiproxy.sh
|
||||
|
||||
* Make a request to the proxy
|
||||
|
||||
curl -v <API_URL>/test
|
||||
|
||||
Note: The API_URL is returned as a terraform output
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [analytics_region](variables.tf#L27) | Region. | <code>string</code> | ✓ | |
|
||||
| [instance_region](variables.tf#L32) | Region. | <code>string</code> | ✓ | |
|
||||
| [network_config](variables.tf#L37) | Network configuration. | <code title="object({ subnet_ip_cidr_range = string subnet_psc_ip_cidr_range = string subnet_proxy_only_ip_cidr_range = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L46) | Project ID. | <code>string</code> | ✓ | |
|
||||
| [_testing](variables.tf#L17) | Populate this variable to avoid triggering the data source. | <code title="object({ name = string number = number services_enabled = optional(list(string), []) })">object({…})</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [api_url](outputs.tf#L17) | API url. | |
|
||||
<!-- END TFDOC -->
|
||||
## Test
|
||||
|
||||
```hcl
|
||||
module "recipe_apigee_swp" {
|
||||
source = "./fabric/modules/apigee/recipe-apigee-swp"
|
||||
project_id = "project-1"
|
||||
_testing = {
|
||||
name = "project-1"
|
||||
number = 1234567890
|
||||
}
|
||||
instance_region = "europe-west1"
|
||||
analytics_region = "europe-west1"
|
||||
network_config = {
|
||||
subnet_ip_cidr_range = "10.16.0.0/24"
|
||||
subnet_psc_ip_cidr_range = "10.16.1.0/24"
|
||||
subnet_proxy_only_ip_cidr_range = "10.16.2.0/24"
|
||||
}
|
||||
}
|
||||
# tftest modules=10 resources=43
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
Copyright 2025 Google LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<ProxyEndpoint name="default">
|
||||
<HTTPProxyConnection>
|
||||
<BasePath>/test</BasePath>
|
||||
</HTTPProxyConnection>
|
||||
<RouteRule name="default">
|
||||
<TargetEndpoint>default</TargetEndpoint>
|
||||
</RouteRule>
|
||||
</ProxyEndpoint>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<TargetEndpoint name="default">
|
||||
<PreFlow name="PreFlow">
|
||||
<Request />
|
||||
<Response />
|
||||
</PreFlow>
|
||||
<Flows />
|
||||
<PostFlow name="PostFlow">
|
||||
<Request />
|
||||
<Response />
|
||||
</PostFlow>
|
||||
<HTTPTargetConnection>
|
||||
<URL>http://10.16.0.4</URL>
|
||||
</HTTPTargetConnection>
|
||||
</TargetEndpoint>
|
||||
19
modules/apigee/recipe-apigee-swp/bundle/apiproxy/test.xml
Normal file
19
modules/apigee/recipe-apigee-swp/bundle/apiproxy/test.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
Copyright 2025 Google LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<APIProxy revision="1" name="test">
|
||||
<Description>test</Description>
|
||||
</APIProxy>
|
||||
BIN
modules/apigee/recipe-apigee-swp/diagram.png
Normal file
BIN
modules/apigee/recipe-apigee-swp/diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
257
modules/apigee/recipe-apigee-swp/main.tf
Normal file
257
modules/apigee/recipe-apigee-swp/main.tf
Normal file
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
# Added this because there is a bug on the provider
|
||||
|
||||
provider "google" {
|
||||
region = var.instance_region
|
||||
}
|
||||
|
||||
locals {
|
||||
hostname = "${module.addresses.global_addresses.apigee.address}.nip.io"
|
||||
environment = "dev"
|
||||
envgroup = "apis"
|
||||
environments = {
|
||||
(local.environment) = {
|
||||
envgroups = [local.envgroup]
|
||||
forward_proxy_uri = "http://${module.apigee.endpoint_attachment_hosts["swp"]}:8080"
|
||||
}
|
||||
}
|
||||
instances = {
|
||||
(var.instance_region) = {
|
||||
environments = keys(local.environments)
|
||||
} }
|
||||
}
|
||||
|
||||
|
||||
module "project" {
|
||||
source = "../../../modules/project"
|
||||
name = var.project_id
|
||||
project_reuse = {
|
||||
use_data_source = var._testing == null
|
||||
project_attributes = var._testing
|
||||
}
|
||||
services = [
|
||||
"apigee.googleapis.com",
|
||||
"compute.googleapis.com",
|
||||
"networksecurity.googleapis.com",
|
||||
"networkservices.googleapis.com",
|
||||
]
|
||||
}
|
||||
|
||||
module "vpc" {
|
||||
source = "../../../modules/net-vpc"
|
||||
project_id = module.project.id
|
||||
name = "vpc"
|
||||
subnets = [
|
||||
{
|
||||
ip_cidr_range = var.network_config.subnet_ip_cidr_range
|
||||
name = "subnet-${var.instance_region}"
|
||||
region = var.instance_region
|
||||
}
|
||||
]
|
||||
subnets_psc = [
|
||||
{
|
||||
ip_cidr_range = var.network_config.subnet_psc_ip_cidr_range
|
||||
name = "subnet-psc-${var.instance_region}"
|
||||
region = var.instance_region
|
||||
}
|
||||
]
|
||||
subnets_proxy_only = [
|
||||
{
|
||||
ip_cidr_range = var.network_config.subnet_proxy_only_ip_cidr_range
|
||||
name = "subnet-proxy-only-${var.instance_region}"
|
||||
region = var.instance_region
|
||||
active = true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module "firewall" {
|
||||
source = "../../../modules/net-vpc-firewall"
|
||||
project_id = module.project.id
|
||||
network = module.vpc.name
|
||||
default_rules_config = {
|
||||
disabled = true
|
||||
}
|
||||
ingress_rules = {
|
||||
allow-ingress-http = {
|
||||
description = "Allow ingress to http servers."
|
||||
targets = ["http-server"]
|
||||
rules = [{ protocol = "tcp", ports = [80] }]
|
||||
source_ranges = [var.network_config.subnet_proxy_only_ip_cidr_range]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "apigee" {
|
||||
source = "../../../modules/apigee"
|
||||
project_id = module.project.project_id
|
||||
organization = {
|
||||
analytics_region = var.analytics_region
|
||||
billing_type = "EVALUATION"
|
||||
runtime_type = "CLOUD"
|
||||
retention = "MINIMUM"
|
||||
disable_vpc_peering = true
|
||||
}
|
||||
envgroups = {
|
||||
"apis" = [local.hostname]
|
||||
}
|
||||
environments = local.environments
|
||||
instances = local.instances
|
||||
endpoint_attachments = {
|
||||
swp = {
|
||||
region = var.instance_region
|
||||
service_attachment = module.swp.service_attachment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "ext_lb" {
|
||||
source = "../../../modules/net-lb-app-ext"
|
||||
name = "glb"
|
||||
project_id = module.project.id
|
||||
forwarding_rules_config = {
|
||||
"" = {
|
||||
address = (
|
||||
module.addresses.global_addresses.apigee.address
|
||||
)
|
||||
}
|
||||
}
|
||||
protocol = "HTTPS"
|
||||
use_classic_version = false
|
||||
backend_service_configs = {
|
||||
default = {
|
||||
backends = [for k, v in module.apigee.instances : { backend = "neg-${k}" }]
|
||||
protocol = "HTTPS"
|
||||
health_checks = []
|
||||
}
|
||||
}
|
||||
neg_configs = {
|
||||
for k, v in module.apigee.instances :
|
||||
"neg-${k}" => { psc = {
|
||||
region = k
|
||||
target_service = v.service_attachment
|
||||
network = module.vpc.self_link
|
||||
subnetwork = module.vpc.subnets_psc["${var.instance_region}/subnet-psc-${var.instance_region}"].self_link
|
||||
}
|
||||
}
|
||||
}
|
||||
ssl_certificates = {
|
||||
managed_configs = {
|
||||
default = {
|
||||
domains = [local.hostname]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "swp" {
|
||||
source = "../../../modules/net-swp"
|
||||
project_id = module.project.id
|
||||
region = var.instance_region
|
||||
name = "gateway"
|
||||
network = module.vpc.id
|
||||
subnetwork = module.vpc.subnet_self_links["${var.instance_region}/subnet-${var.instance_region}"]
|
||||
gateway_config = {
|
||||
addresses = [module.addresses.internal_addresses["gateway"].address]
|
||||
ports = [8080]
|
||||
}
|
||||
service_attachment = {
|
||||
nat_subnets = [module.vpc.subnets_psc["${var.instance_region}/subnet-psc-${var.instance_region}"].self_link]
|
||||
automatic_connection = true
|
||||
}
|
||||
policy_rules = {
|
||||
allowed-hosts = {
|
||||
priority = 1000
|
||||
allow = true
|
||||
session_matcher = "host() == '${module.nginx_vm.internal_ip}'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "addresses" {
|
||||
source = "../../../modules/net-address"
|
||||
project_id = module.project.project_id
|
||||
internal_addresses = {
|
||||
gateway = {
|
||||
region = var.instance_region
|
||||
subnetwork = module.vpc.subnet_self_links["${var.instance_region}/subnet-${var.instance_region}"]
|
||||
}
|
||||
}
|
||||
global_addresses = {
|
||||
apigee = {}
|
||||
}
|
||||
}
|
||||
|
||||
module "nginx_vm" {
|
||||
source = "../../../modules/compute-vm"
|
||||
project_id = module.project.project_id
|
||||
zone = "${var.instance_region}-b"
|
||||
name = "nginx"
|
||||
network_interfaces = [{
|
||||
network = module.vpc.self_link
|
||||
subnetwork = module.vpc.subnet_self_links["${var.instance_region}/subnet-${var.instance_region}"]
|
||||
}]
|
||||
metadata = {
|
||||
startup-script = <<-EOF
|
||||
#! /bin/bash
|
||||
apt-get update
|
||||
apt-get install -y nginx
|
||||
EOF
|
||||
}
|
||||
service_account = {
|
||||
auto_create = true
|
||||
}
|
||||
tags = [
|
||||
"http-server"
|
||||
]
|
||||
}
|
||||
|
||||
resource "local_file" "target_endpoint_file" {
|
||||
content = templatefile("${path.module}/templates/targets/default.xml.tpl", {
|
||||
ip_address = module.nginx_vm.internal_ip
|
||||
})
|
||||
filename = "${path.module}/bundle/apiproxy/targets/default.xml"
|
||||
file_permission = "0644"
|
||||
}
|
||||
|
||||
# tflint-ignore: terraform_unused_declarations
|
||||
data "archive_file" "bundle" {
|
||||
type = "zip"
|
||||
source_dir = "${path.module}/bundle"
|
||||
output_path = "${path.module}/bundle.zip"
|
||||
depends_on = [
|
||||
local_file.target_endpoint_file
|
||||
]
|
||||
}
|
||||
|
||||
resource "local_file" "deploy_apiproxy_file" {
|
||||
content = templatefile("${path.module}/templates/deploy-apiproxy.sh.tpl", {
|
||||
organization = module.apigee.org_name
|
||||
environment = local.environment
|
||||
})
|
||||
filename = "${path.module}/deploy-apiproxy.sh"
|
||||
file_permission = "0755"
|
||||
}
|
||||
|
||||
module "nat" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
project_id = module.project.project_id
|
||||
region = var.instance_region
|
||||
name = "nat-${var.instance_region}"
|
||||
router_network = module.vpc.self_link
|
||||
}
|
||||
20
modules/apigee/recipe-apigee-swp/outputs.tf
Normal file
20
modules/apigee/recipe-apigee-swp/outputs.tf
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
output "api_url" {
|
||||
description = "API url."
|
||||
value = "https://${local.hostname}/test"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
ORGANIZATION=${organization}
|
||||
ENVIRONMENT=${environment}
|
||||
|
||||
export TOKEN=$(gcloud auth print-access-token)
|
||||
|
||||
curl -v -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type:application/octet-stream" \
|
||||
-T 'bundle.zip' \
|
||||
"https://apigee.googleapis.com/v1/organizations/$ORGANIZATION/apis?name=test&action=import"
|
||||
|
||||
curl -v -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://apigee.googleapis.com/v1/organizations/$ORGANIZATION/environments/$ENVIRONMENT/apis/test/revisions/1/deployments"
|
||||
|
||||
curl -v \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://apigee.googleapis.com/v1/organizations/$ORGANIZATION/environments/$ENVIRONMENT/apis/test/revisions/1/deployments"
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<TargetEndpoint name="default">
|
||||
<PreFlow name="PreFlow">
|
||||
<Request />
|
||||
<Response />
|
||||
</PreFlow>
|
||||
<Flows />
|
||||
<PostFlow name="PostFlow">
|
||||
<Request />
|
||||
<Response />
|
||||
</PostFlow>
|
||||
<HTTPTargetConnection>
|
||||
<URL>http://${ip_address}</URL>
|
||||
</HTTPTargetConnection>
|
||||
</TargetEndpoint>
|
||||
49
modules/apigee/recipe-apigee-swp/variables.tf
Normal file
49
modules/apigee/recipe-apigee-swp/variables.tf
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "_testing" {
|
||||
description = "Populate this variable to avoid triggering the data source."
|
||||
type = object({
|
||||
name = string
|
||||
number = number
|
||||
services_enabled = optional(list(string), [])
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "analytics_region" {
|
||||
description = "Region."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "instance_region" {
|
||||
description = "Region."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "network_config" {
|
||||
description = "Network configuration."
|
||||
type = object({
|
||||
subnet_ip_cidr_range = string
|
||||
subnet_psc_ip_cidr_range = string
|
||||
subnet_proxy_only_ip_cidr_range = string
|
||||
})
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project ID."
|
||||
type = string
|
||||
}
|
||||
Reference in New Issue
Block a user