GAE http request to GCE via Serverless VPC Connector - google-app-engine

I have a Google App Engine app (python 2.7 - it's an old project in the middle of upgrading!) that needs to make queries to an Elastisearch instance on Google Compute Engine. I'm able to make the requests using the GCE public ip address without an issue, but I'd prefer not to expose the GCE instance to the public internet.
The app engine app is in region us-central
The compute engine instance is in region us-central1, zone us-central1-f
The compute engine instance is in vpc network "default". (not a legacy network)
I've set up a Serverless VPC connector in us-central1, on default network.
I've set up the app engine app.yaml to use the connector.
But http requests to the compute engine private IP address (10.128.0.2) get connection failures, and DNS lookups on the internal DNS name for the compute engine fail edit: dns lookup does work using socket.gethostbyname.
error: An error occured while connecting to the server: Unable to connect to server at URL: http://10.128.0.2:9200/indexname
The same request succeeds when using the public IP address (when I open the VPC firewall on port 9200).
Snippet from the app engine app config:
runtime: python27
api_version: '1'
env: standard
threadsafe: false
instance_class: F4
network:
name: default
vpc_access_connector:
name: >-
projects/myproject/locations/us-central1/connectors/connector0301
gcloud beta --account="myaccount" --project="myproject" app describe:
authDomain: gmail.com
codeBucket: staging.myproject.appspot.com
databaseType: CLOUD_DATASTORE_COMPATIBILITY
defaultBucket: myproject.appspot.com
defaultHostname: myproject.appspot.com
featureSettings:
splitHealthChecks: true
useContainerOptimizedOs: true
gcrDomain: us.gcr.io
id: myproject
locationId: us-central
name: apps/myproject
servingStatus: SERVING
gcloud beta --account="myaccount" --project="myproject" compute instances describe (just the network snippet):
networkInterfaces:
- accessConfigs:
- kind: compute#accessConfig
name: External NAT
natIP: SNIPPED
networkTier: PREMIUM
type: ONE_TO_ONE_NAT
fingerprint: M087cXbOWII=
kind: compute#networkInterface
name: nic0
network: https://www.googleapis.com/compute/beta/projects/myproject/global/networks/default
networkIP: 10.128.0.2
subnetwork: https://www.googleapis.com/compute/beta/projects/myproject/regions/us-central1/subnetworks/default
gcloud beta --account="myaccount" --project="myproject" compute networks vpc-access
connectors list --region=us-central1
CONNECTOR_ID REGION NETWORK IP_CIDR_RANGE MIN_THROUGHPUT MAX_THROUGHPUT STATE
connector0301 us-central1 default 10.8.0.0/28 200 300 READY
gcloud beta --account="myaccount" --project="myproject" compute networks vpc-access connectors describe connector0301 --region=us-central1
ipCidrRange: 10.8.0.0/28
maxThroughput: 300
minThroughput: 200
name: projects/myproject/locations/us-central1/connectors/connector0301
network: default
state: READY
gcloud --account="myaccount" --project="myproject" compute firewall-rules describe default-allow-internal
allowed:
- IPProtocol: tcp
ports:
- 0-65535
- IPProtocol: udp
ports:
- 0-65535
- IPProtocol: icmp
creationTimestamp: '2020-02-11T11:18:09.906-08:00'
description: Allow internal traffic on the default network
direction: INGRESS
disabled: false
id: '1434668200291681054'
kind: compute#firewall
logConfig:
enable: true
name: default-allow-internal
network: https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default
priority: 65534
selfLink: https://www.googleapis.com/compute/v1/projects/myproject/global/firewalls/default-allow-internal
sourceRanges:
- 10.128.0.0/9
- 10.8.0.0/28
Do serverless VPC connectors not work for internal IP http requests?

Do serverless VPC connectors not work for internal IP http requests?
Serverless VPC connectors work for internal IP http requests using urllib.request in the python37 runtime, but not using urllib2 or urlfetch from google.appengine.api in the python27 runtime. (Reminder that urllib2 uses urlfetch under the hood on app engine python27)
Since this is part of an older project that is slowly moving from python27 to python37, for now I put the internal ip http requests into a separate service so they could use the new runtime.

Related

Kubernetes Host and Service Ingress Mapping using TCP

While working with Kubernetes for some months now, I found a nice way to use one single existing domain name and expose the cluster-ip through a sub-domain but also most of the microservices through different sub-sub-domains using the ingress controller.
My ingress example code:
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: cluster-ingress-basic
namespace: ingress-basic
selfLink: >-
/apis/networking.k8s.io/v1beta1/namespaces/ingress-basic/ingresses/cluster-ingress-basic
uid: 5d14e959-db5f-413f-8263-858bacc62fa6
resourceVersion: '42220492'
generation: 29
creationTimestamp: '2021-06-23T12:00:16Z'
annotations:
kubernetes.io/ingress.class: nginx
managedFields:
- manager: Mozilla
operation: Update
apiVersion: networking.k8s.io/v1beta1
time: '2021-06-23T12:00:16Z'
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
.: {}
'f:kubernetes.io/ingress.class': {}
'f:spec':
'f:rules': {}
- manager: nginx-ingress-controller
operation: Update
apiVersion: networking.k8s.io/v1beta1
time: '2021-06-23T12:00:45Z'
fieldsType: FieldsV1
fieldsV1:
'f:status':
'f:loadBalancer':
'f:ingress': {}
spec:
rules:
- host: microname1.subdomain.domain.com
http:
paths:
- pathType: ImplementationSpecific
backend:
serviceName: kylin-job-svc
servicePort: 7070
- host: microname2.subdomain.domain.com
http:
paths:
- pathType: ImplementationSpecific
backend:
serviceName: superset
servicePort: 80
- {}
status:
loadBalancer:
ingress:
- ip: xx.xx.xx.xx
With this configuration:
microname1.subdomain.domain.com is pointing into Apache Kylin
microname2.subdomain.domain.com is pointing into Apache Superset
This way all microservices can be exposed using the same Cluster-Load-Balancer(IP) but the different sub-sub domains.
I tried to do the same for the SQL Server but this is not working, not sure why but I have the feeling that the reason is that the SQL Server communicates using TCP and not HTTP.
- host: microname3.subdomain.domain.com
http:
paths:
- pathType: ImplementationSpecific
backend:
serviceName: mssql-linux
servicePort: 1433
Any ideas on how I can do the same for TCP services?
Your understanding is good, by default NGINX Ingress Controller only supports HTTP and HTTPs traffic configuration (Layer 7) so probably your SQL server is not working because of this.
Your SQL service is operating using TCP connections so it is does not take into consideration custom domains that you are trying to setup as they are using same IP address anyway .
The solution for your issue is not use custom sub-domain(s) for this service but to setup exposing TCP service in NGINX Ingress Controller. For example you can setup this SQL service to be available on ingress IP on port 1433:
Ingress controller uses the flags --tcp-services-configmap and --udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: <namespace/service name>:<service port>:[PROXY]:[PROXY]
To setup it you can follow steps provided in official NGINX Ingress documentation but there are also some more detailed instructions on StackOverflow, for example this one.

Unable to Deploy Application to App Engine Flexible Environment with a Shared VPC

I am unable to deploy a Dockerized application to App Engine Flexible Environment (AEF) in a Google Cloud Platform (GCP) project with a provisioned Shared Virtual Private Cloud (XPN).
In other words, my application with the following app.yaml:
automatic_scaling:
max_num_instances: 1
min_num_instances: 1
env: flex
network:
instance_tag: incorrect-target-tag
name: projects/$GCP_PROJECT_ID/global/networks/$XPN_NETWORK_NAME
service: $AEF_APPLICATION_NAME
and a confirmed Docker image name and tag in Google Container Registry (GCR):
gcloud container images list-tags \
us.gcr.io/$GCP_PROJECT_NAME/$AEF_APPLICATION_NAME \
--flatten=tags \
--format='value(format("us.gcr.io/$GCP_PROJECT_NAME/$AEF_APPLICATION_NAME:{0}", tags))' \
--project=$GCP_PROJECT_NAME
#=>
. . .
us.gcr.io/$GCP_PROJECT_NAME/$AEF_APPLICATION_NAME:$DOCKER_IMAGE_TAG
. . .
is unable to be deployed to AEF:
yes | gcloud app deploy \
--appyaml=./app.yaml \
--image-url=us.gcr.io/$GCP_PROJECT_NAME/$AEF_APPLICATION_NAME:$DOCKER_IMAGE_TAG
#=>
Services to deploy:
descriptor: [/. . ./app.yaml]
source: [/. . ./$AEF_APPLICATION_NAME]
target project: [$GCP_PROJECT_NAME]
target service: [$AEF_APPLICATION_NAME]
target version: [$AEF_APPLICATION_VERSION]
target url: [. . .]
target service account: [App Engine default service account]
Do you want to continue (Y/n)?
Beginning deployment of service [$AEF_APPLICATION_NAME]...
WARNING: Deployment of service [$AEF_APPLICATION_NAME] will ignore the skip_files field in the configuration file, because the image has already been built.
Updating service [$AEF_APPLICATION_NAME] (this may take several minutes)...
.............................................................failed.
ERROR: (gcloud.app.deploy) Error Response: [13] Flex operation projects/$GCP_PROJECT_NAME/regions/$AEF_APPLICATION_REGION/operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx error [INTERNAL]: An internal error occurred while processing task /app-engine-flex/insert_flex_deployment/flex_create_resources>1970-01-01T00:00:00.001Z000001.jc.2: <eye3 title='FAILED_PRECONDITION'/> generic::FAILED_PRECONDITION: Validation error: The App Engine flexible Environment Service Agent is unable to find a suitable Flex Firewall Rule in network '$XPN_NETWORK_NAME' in project '$GCP_PROJECT_ID'. Have the Shared VPC Admin create a Flex Firewall Rule as described in https://cloud.google.com/appengine/docs/flexible/python/using-shared-vpc
with the following Virtual Private Cloud (VPC) firewall rule supporting AEF communication through the XPN:
cloud compute firewall-rules list \
--filter="allowed[].ports=(8443) AND allowed[].ports=(10402)" \
--project=$GCP_PROJECT_NAME
#=>
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
aef-instance $XPN_NETWORK_NAME INGRESS 1000 tcp:8443,tcp:10402 False
To show all fields of the firewall, please show in JSON format: --format=json
To show all fields in table format, please see the examples in --help.
gcloud compute firewall-rules describe \
aef-instance \
--format=yaml \
--project=$GCP_PROJECT_NAME
#=>
allowed:
- IPProtocol: tcp
ports:
- '8443'
- '10402'
creationTimestamp: '1970-01-01T00:00:00.000-01:00'
description: allows traffic between aef and xpn
direction: INGRESS
disabled: false
id: 'xxxxxxxxxxxxxxxxxxx'
kind: compute#firewall
logConfig:
enable: false
name: aef-instance
network: https://www.googleapis.com/compute/v1/projects/$GCP_PROJECT_NAME/global/networks/$XPN_NETWORK_NAME
priority: 1000
selfLink: https://www.googleapis.com/compute/v1/projects/$GCP_PROJECT_NAME/global/firewalls/aef-instance
sourceRanges:
- 35.191.0.0/16
- 130.211.0.0/22
targetTags:
- incorrect-target-tag
Note: this rule is required for using any AEF application with the XPN, described here.
Following the guide to linking AEF and the XPN here, the target tag for VPC Firewall rule aef-instance MUST be aef-instance. Update VPC Firewall rule aef-instance with the correct target tag:
gcloud compute firewall-rules update \
aef-instance \
--project=$GCP_PROJECT_NAME \
--target-tags=aef-instance
#=>
Updated [https://www.googleapis.com/compute/v1/projects/$GCP_PROJECT_NAME/global/firewalls/aef-instance].
and you will be able to redeploy to AEF without that validation error.
Note: changing the target tag in the app.yaml isn't necessary: the AEF application will be able to communicate over a provisioned XPN as long as there is a firewall rule that meets this criteria exactly, regardless of tags specified in the app.yaml.

Connectivity issues from App Engine to CloudSQL using Private IP and Serverless VPC Access

I am doing a PoC to connect from Google App Engine to CloudSQL instance running with Private IP on a SharedVPC . The sample application for testing is from
https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/cloud-sql/mysql/sqlalchemy/README.md
My Serverless VPC Connector Range is as follows
$ gcloud compute networks vpc-access connectors list --region=us-central1
CONNECTOR_ID REGION NETWORK IP_CIDR_RANGE MIN_THROUGHPUT MAX_THROUGHPUT STATE
testserverlessvpc us-central1 kube-shared-vpc 192.168.60.0/28 200 300 READY
Private IP Range is as follows
$ gcloud compute addresses list --global --filter="purpose=VPC_PEERING"
NAME ADDRESS/RANGE TYPE PURPOSE NETWORK REGION SUBNET STATUS
cloudsqltestrangenew 10.0.100.0/20 INTERNAL VPC_PEERING kube-shared-vpc RESERVED
MySQL instance is as follows
$ gcloud sql instances list
NAME DATABASE_VERSION LOCATION TIER PRIMARY_ADDRESS PRIVATE_ADDRESS STATUS
mysql2 MYSQL_5_7 us-central1-b db-f1-micro - 10.0.100.5 RUNNABLE
app.standard.yaml is as follows
runtime: python37
service: appcentralpri
env_variables:
CLOUD_SQL_CONNECTION_NAME: projectname:us-central1:mysql2
DB_USER: guestdb
DB_PASS: password
DB_NAME: testdb
DB_HOST: 10.0.100.5:3306
vpc_access_connector:
name: projects/hostproject-26a2/locations/us-central1/connectors/testserverlessvpc
Deployment went through fine and no errors in log encountered
gcloud app deploy app.standard.yaml
However when I try to connect to the application endpoint , the page is not accessible with "Server Not Found"
I have given VPC Access and Network Compute User role to the below App Engine Default Service account on VPC Host Project
<hostproject>-26a2#appspot.gserviceaccount.com
UPDATES
Also added below in app.yaml but no luck
env_variables:
GAE_USE_SOCKETS_HTTPLIB : 'anyvalue'
https://cloud.google.com/appengine/docs/standard/python/sockets#making_httplib_use_sockets
Same setup for CloudRun and CloudSQL worked for me but struggling with GAE. Any suggestions to resolve this issue ?
Your app.yaml file is wrong formatted. The vpc_access_connector: need to be at the root level. Here it's taken as an environment variable value.
runtime: python37
service: appcentralpri
env_variables:
CLOUD_SQL_CONNECTION_NAME: projectname:us-central1:mysql2
DB_USER: guestdb
DB_PASS: password
DB_NAME: testdb
DB_HOST: 10.0.100.5:3306
vpc_access_connector:
name: projects/hostproject-26a2/locations/us-central1/connectors/testserverlessvpc

how to specify network name in app.yaml for asp.net core webapi deployed in Google appengine

I am trying to deploy an asp.net core webapi to google appengine flex. If you don't mention network name in app.yaml then it takes default.
In my case there is no default network. I have to explicitly specify the network name and subnetwork_name in my app.yaml. This project where I am trying to deploy my api in appengine flex is in a shared VPC.This is why I am specifying the complete path, "projects/myorg-npe-232f/global/networks/myorg-shared-network". Please refer the app.yaml below -
runtime: aspnetcore
env: flex
service: default
api_version: 1.1
network:
name: projects/myorg-npe-232f/global/networks/myorg-shared-network
subnetwork_name: myorg-exxc-bbdf-subnet-central
I am getting the below error -
Unable to assign value 'projects/myorg-npe-232f/global/networks/myorg-shared-network' to attribute 'name':
value 'projects/myorg-npe-232f/global/networks/myorg-shared-network' for name does not match expression '^(?:^[a-z]([a-z\d-]{0,61}[a-z\d])?$)$' in app.yaml
As explained in the documentation here:
In a service project, App Engine Flexible resources cannot participate
in Shared VPC.
You may want to consider VPC Peering instead if it fits your use case.
Once the firewall rule and proper permissions are set up, can be deployed either a new or an existing of App Engine flexible ENV service into Shared VPC network, check the parameters in the manifest file:
network:
name: projects/HOST_PROJECT_ID/global/networks/NETWORK_NAME
subnetwork_name: SUBNETWORK_NAME
If you are using AppEngine flex, you can use the same settings.
However, make sure the vpc subnet exists, permissions and the firewall rule setup, I was getting the exact same error when I did not provide subnetwork_name.
Re: https://cloud.google.com/appengine/docs/flexible/dotnet/using-shared-vpc
network:
name: projects/project-id/global/networks/myorg-shared-vpc
session_affinity: true
subnetwork_name: mycompany-develop-us-central1
Another update:
Found this same issue with a co-worker, fixed it by updating the cloud commandline client.

App Engine Flex - Setting GCP Network Tag

How can I apply a GCP firewall rule tag to an App Engine Flex instance? I have a project where a bastion host is set up with the appropriate firewall rules to only allow ssh from 0.0.0.0/0 to the bh machine. Then the bastion host is the only source that is able to connect via ssh to all project VMs. I need to apply a firewall rule tag "restricted-ssh" to all app engine flex instances to allow ssh in debug mode.
Per documentation: A target, which defines the instances (including GKE clusters and App Engine Flex instances) to which the rule will apply.
Source: https://cloud.google.com/vpc/docs/firewalls
Looks like the GCP VPC firewall rules effect app engine flex instance. How do I apply a firewall tag to all flex instances?
Inside your app.yaml file, there's an optional network section which has an instance_tag key that seems to be what you're looking for, so you'll end up having something like this (for a sample Python app):
runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app
[...]
network:
instance_tag: restricted_ssh
Reference: https://cloud.google.com/appengine/docs/flexible/python/reference/app-yaml#network_settings

Resources