Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions samples/x-nb-psc-sb-psc-ilb-crun/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.env
.terraform.lock.hcl
terraform.tfstate.backup
terraform.tfstate
.terraform.tfstate.lock.info
.DS_Store
AM-SetAudience.xml
.terraform
119 changes: 119 additions & 0 deletions samples/x-nb-psc-sb-psc-ilb-crun/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# How to consume internal Cloud Run apps from Apigee X using a single Service Attachment

## Overview

This sample emphasises on the southbound connectivity based on
Private Service Connect (PSC) to communicate with internal Cloud Run
applications through an internal HTTPS (L7) load balancer.

![Use case overview](./pictures/overview.png)

An internal HTTPS load balancer (L7 ILB) is used to serve several Cloud Run apps using Serverless NEG and URL Mask.

A serverless NEG backend can point to several Cloud Run services.

A URL mask is a template of your URL schema. The serverless NEG uses this template to map the request to the appropriate service.

The L7 ILB is accessed through a PSC Service Attachment that can be reached by an ApigeeX instance via a PSC endpoint Attachment. These two attachments (Endpoint and Service attachments) must be part of the same GCP region.

Apigee X uses a target endpoint to reach the L7 ILB through the PSC channel. This target endpoint is configured in HTTPS and uses a dedicated hostname (the hostname of the l7 ILB). Therefore we need two DNS resolutions:

- The first on Apigee X (target endpoint) to point to the PSC endpoint attachment: a private Cloud DNS (A record) and a DNS peering are required to manage the resolution. This private zone is configured on the consumer VPC (named apigee-network in the picture above) that is peered with the Apigee X VPC. The DNS peering is configured between the two VPCs for a particular domain (iloveapis.io in the example above)
- The second on the PSC service attachment to point to the L7 ILB: a private Cloud DNS (A record) is required to manage the resolution. This private zone is configured on the VPC (named ilb-network in the picture above). Note that the L7 ILB presents an SSL certificate used to establish a secured communication

An identity token (ID token) is required to consume the different Cloud Run services.
This ID token is generated on Apigee X and transmitted as a bearer token to the Cloud Run apps.

A service account (```sa_apigee_apiproxy```) is created for this purpose and used to deplpy the API proxy (```cloudrun-api-v1```) on the Apigee X instance.
The permission of this service account is ``` roles/run.invoker ```

## Setup Instructions

You can implement a full or partial install of the sample

### Full installation: Apigee X (PSC NB) + Southbound connectivity to Cloud Run apps using PSC

For this type of installation, we consider that an Apigee X instance has already been provisionned.

### Partial installation: Southbound connectivity to Cloud Run apps using PSC

For this type of installation, we consider that an Apigee X instance has already been provisionned.

We do not care about the existing northbopund connectivity, which can rely on VPC peering or PSC.

Our focus here is the deployment of 3 (basic) internal Cloud Run services and the network components
to consume them from the Apigee X instance. Apigee is of course used to expose these services
as APIs and API products.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_google"></a> [google](#requirement\_google) | 4.58.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_google"></a> [google](#provider\_google) | 4.58.0 |
| <a name="provider_null"></a> [null](#provider\_null) | 3.2.1 |
| <a name="provider_tls"></a> [tls](#provider\_tls) | 4.0.4 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_cloud_run"></a> [cloud\_run](#module\_cloud\_run) | GoogleCloudPlatform/cloud-run/google | ~> 0.2.0 |

## Resources

| Name | Type |
|------|------|
| [google_apigee_endpoint_attachment.endpoint_attachment](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/apigee_endpoint_attachment) | resource |
| [google_artifact_registry_repository.docker-main](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/artifact_registry_repository) | resource |
| [google_compute_address.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_address) | resource |
| [google_compute_forwarding_rule.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_forwarding_rule) | resource |
| [google_compute_network.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_network) | resource |
| [google_compute_region_backend_service.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_region_backend_service) | resource |
| [google_compute_region_network_endpoint_group.cloudrun_neg](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_region_network_endpoint_group) | resource |
| [google_compute_region_ssl_certificate.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_region_ssl_certificate) | resource |
| [google_compute_region_target_https_proxy.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_region_target_https_proxy) | resource |
| [google_compute_region_url_map.https_lb](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_region_url_map) | resource |
| [google_compute_service_attachment.psc_ilb_service_attachment](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_service_attachment) | resource |
| [google_compute_subnetwork.default](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_subnetwork) | resource |
| [google_compute_subnetwork.proxy_subnet](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_subnetwork) | resource |
| [google_compute_subnetwork.psc_ilb_nat](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/compute_subnetwork) | resource |
| [google_dns_managed_zone.private-zone-apigee](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/dns_managed_zone) | resource |
| [google_dns_managed_zone.private-zone-ilb](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/dns_managed_zone) | resource |
| [google_dns_record_set.a-apigee](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/dns_record_set) | resource |
| [google_dns_record_set.a-ilb](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/dns_record_set) | resource |
| [google_project_iam_member.sa_apigee_apiproxy](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/project_iam_member) | resource |
| [google_project_service.gcp_services](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/project_service) | resource |
| [google_service_account.service_account_apiproxy](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/service_account) | resource |
| [google_service_networking_peered_dns_domain.apigee](https://registry.terraform.io/providers/hashicorp/google/4.58.0/docs/resources/service_networking_peered_dns_domain) | resource |
| [null_resource.login_image_build](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
| [null_resource.search_image_build](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
| [null_resource.translate_image_build](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
| [tls_private_key.default](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
| [tls_self_signed_cert.default](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/self_signed_cert) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_apigee_endpoint_attachment"></a> [apigee\_endpoint\_attachment](#input\_apigee\_endpoint\_attachment) | Apigee endpoint attachment value. | `string` | n/a | yes |
| <a name="input_consumer_vpc"></a> [consumer\_vpc](#input\_consumer\_vpc) | Consumer VPC network name. | `string` | n/a | yes |
| <a name="input_gcp_project_id"></a> [gcp\_project\_id](#input\_gcp\_project\_id) | The GCP project ID to create the gcp resources in. | `string` | n/a | yes |
| <a name="input_gcp_region"></a> [gcp\_region](#input\_gcp\_region) | The GCP region to create the gcp resources in. | `string` | n/a | yes |
| <a name="input_gcp_service_list"></a> [gcp\_service\_list](#input\_gcp\_service\_list) | The list of required Google apis | `list(string)` | <pre>[<br> "artifactregistry.googleapis.com",<br> "cloudbuild.googleapis.com",<br> "run.googleapis.com",<br> "dns.googleapis.com",<br> "compute.googleapis.com",<br> "logging.googleapis.com",<br> "monitoring.googleapis.com"<br>]</pre> | no |
| <a name="input_gcp_zone"></a> [gcp\_zone](#input\_gcp\_zone) | The GCP zone to create the gcp resources in. | `string` | n/a | yes |
| <a name="input_repository_id"></a> [repository\_id](#input\_repository\_id) | Repository id of the artifact registry. | `string` | n/a | yes |
| <a name="input_url_mask"></a> [url\_mask](#input\_url\_mask) | URL mask of the serverless network endpoint group (neg). | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_service_urls"></a> [service\_urls](#output\_service\_urls) | Cloud Run service URLs |
<!-- END_TF_DOCS -->
44 changes: 44 additions & 0 deletions samples/x-nb-psc-sb-psc-ilb-crun/cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh
# Copyright 2023 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.

set -e

SCRIPTPATH="$( cd "$(dirname "$0")" || exit >/dev/null 2>&1 ; pwd -P )"

# Ask for input parameters if they are not set

[ -z "$GCP_PROJECT_ID" ] && printf "GCP project id: " && read -r GCP_PROJECT_ID

###
### destroy_common_gcp_resources()
###
destroy_common_gcp_resources() {

terraform init
terraform destroy --var-file="./input.tfvars" \
-var "gcp_project_id=${GCP_PROJECT_ID}"
-auto-approve
}

##
###
### destroy_common_gcp_resources()
###
main() {
cd ${SCRIPTPATH}
destroy_common_gcp_resources
}

main "${@}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Copyright 2023 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="cloudrun-api-v1"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Copyright 2023 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.
-->
<RaiseFault name="RF-404NotFound">
<FaultResponse>
<Set>
<Headers/>
<Payload contentType="application/json">{"error":"not_found"}</Payload>
<StatusCode>404</StatusCode>
<ReasonPhrase>Not Found</ReasonPhrase>
</Set>
</FaultResponse>
</RaiseFault>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Copyright 2023 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">
<PreFlow name="PreFlow"/>
<Flows>
<Flow name="GET /login">
<Condition>(proxy.pathsuffix MatchesPath "/login") and (request.verb = "GET")</Condition>
<Request/>
<Response/>
</Flow>
<Flow name="GET /search">
<Condition>(proxy.pathsuffix MatchesPath "/search") and (request.verb = "GET")</Condition>
<Request/>
<Response/>
</Flow>
<Flow name="GET /translate">
<Condition>(proxy.pathsuffix MatchesPath "/translate") and (request.verb = "GET")</Condition>
<Request/>
<Response/>
</Flow>
<Flow name="404 - Not Found">
<Request>
<Step>
<Name>RF-404NotFound</Name>
</Step>
</Request>
<Response/>
</Flow>
</Flows>
<PostFlow name="PostFlow">
<Request>
<Step>
<Name>AM-SetAudience</Name>
</Step>
</Request>
<Response/>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/v1/crun</BasePath>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
</ProxyEndpoint>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Copyright 2023 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.
-->
<TargetEndpoint name="default">
<PreFlow name="PreFlow"/>
<Flows/>
<PostFlow name="PostFlow"/>
<HTTPTargetConnection>
<URL>https://internal.example.com</URL>
<Authentication>
<GoogleIDToken>
<Audience ref="flow.audience"/>
</GoogleIDToken>
</Authentication>
</HTTPTargetConnection>
</TargetEndpoint>
41 changes: 41 additions & 0 deletions samples/x-nb-psc-sb-psc-ilb-crun/input.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright 2023 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.
*/

/**
** gcp variables
*/
gcp_region = "europe-west1"
gcp_zone = "europe-west1-b"

/**
** artifact registry variables
*/
repository_id = "docker-main"

/**
** serverless neg variables
*/
url_mask = "/<service>"

/**
** name of the apigee endpoint attachment
*/
apigee_endpoint_attachment = "pscendpoint"

/**
** consumer vpc network name
*/
consumer_vpc = "apigee-network"
Loading