I would like to have a service in appengine flexible that has a UDP server that takes incoming udp traffic on a given port and redirects it to another service in appengine standard that uses HTTPS.
It is my understanding that flex environment allows opening UDP listen sockets and indeed my application starts the server OK. However, I cannot make any traffic reach the UDP server.
I suspect the problem is a GAE or Docker configuration problem but I cannot find documentation or similar issues online to solve it. All Google documentation for appengine flexible is around HTTPS. So any guidance would be helpful. I have several questions that I believe relate to my understanding on Flexible Appengine, the VM and Docker:
Is flex appengine supposed to be used at all as a UDP server? lack
of documentation on UDP load balancing seems to indicate me no...
Any ideas if this is on the roadmap?
If supported, to which IP/URL should I direct my UDP traffic? Is it to my-project . appspot . com or to each of the individual VM instances (would seem like a bad idea since VMs are ephemeral)?
This is my current application
app.yaml
As you can see I forwarded my listen UDP port as explained here
runtime: python
env: flex
entrypoint: python main.py
runtime_config:
python_version: 2
network:
forwarded_ports:
- 13949/udp
service: udp-gateway
# This sample incurs costs to run on the App Engine flexible environment.
# The settings below are to reduce costs during testing and are not appropriate
# for production use. For more information, see:
# https://cloud.google.com/appengine/docs/flexible/python/configuring-your-app-with-app-yaml
manual_scaling:
instances: 1
resources:
cpu: 1
memory_gb: 0.5
disk_size_gb: 10
For the server I am using python SocketServer in threaded mode and I am keeping my main thread in an infinite loop in order not to exit the server.
I have also added a firewall rule in my GCP console:
{
"allowed": [
{
"IPProtocol": "udp",
"ports": [
"13949"
]
}
],
"creationTimestamp": "2018-02-24T16:39:24.282-08:00",
"description": "allow udp incoming on 13949",
"direction": "INGRESS",
"id": "4340622718970870611",
"kind": "compute#firewall",
"name": "allow-udp-13949",
"network": "projects/xxxxxx/global/networks/default",
"priority": 1000,
"selfLink": "projects/xxxxx/global/firewalls/allow-udp-13949",
"sourceRanges": [
"0.0.0.0/0"
]
}
So I ended up being able to answer my own questions (thanks SO for allowing me to put down my thoughts, it helps :))
Indeed, flex environment only features a load balancer for HTTPS, which means that even if it is possible to open UDP sockets, it is not meant to be used as an UDP server. I have not found any evidence, Google plans to add support for UDP/TCP load balancing for Appengine flex. The next service that offers UDP load balancing is Kubernetes Engine (and Compute Engine of course). So that is where I am headed now.
With the configuration described in the OP, I could make traffic reach my application by addressing individual instances' IP. However, this is not meant to be used in a production application since instances are ephemeral and also does not scale (would need to do my own load balancer which is out of the question),
Related
In Google Cloud, I have an application deployed in Kubernetes in one project (call it Project-A), and another deployed in App Engine (call it Project-B). Project-A has a cloud NAT created using automatic IP. Project-B uses App Engine standard.
Project-B by default allows ingress traffic from the internet. However, I only want Project-A to communicate with Project-B. All other traffic needs to be blocked.
I currently do not have any shared VPC configured.
In Project-B, I configure the App Engine Firewall rules with the following deny rules (the list below is shown in the order of the firewall rule priority defined in App Engine Firewall):
0.0.0.1/32
0.0.0.2/31
0.0.0.4/30
0.0.0.8/29
0.0.0.16/28
0.0.0.32/27
0.0.0.64/26
0.0.0.128/25
0.0.1.0/24
0.0.2.0/23
0.0.4.0/22
0.0.8.0/21
0.0.16.0/20
0.0.32.0/19
0.0.64.0/18
0.0.128.0/17
0.1.0.0/16
0.2.0.0/15
0.4.0.0/14
0.8.0.0/13
0.16.0.0/12
0.32.0.0/11
0.64.0.0/10
0.128.0.0/9
1.0.0.0/8
2.0.0.0/7
4.0.0.0/6
8.0.0.0/5
16.0.0.0/4
32.0.0.0/3
64.0.0.0/2
128.0.0.0/1
default rule: allow *
(the CIDR blocks above correspond to 0.0.0.1 - 255.255.255.255; I used https://www.ipaddressguide.com/cidr to perform the calculation for me).
From Project-A, I am still able to reach Project-B. Is there some kind of internal network routing that Google does which bypasses the App Engine firewall? It seems like in this case, Google is using the default rule and ignoring all my other rules.
I then did the reverse. The rules for all those CIDR blocks above were changed to ALLOW, while the last default rule was changed to DENY for all IPs. I then got the reverse behaviour - Project-A is unable to reach Project-B. Again, it looks like only the default rule is being used.
How can I achieve the situation where only Project-A can communicate with Project-B, no internet ingress traffic is allowed to reach Project-B? Can I avoid using a shared VPC? If I do use a shared VPC, what should the App Engine firewall rules be for Project-B?
Sure. I ended up going with the load balancer solution. This gives me a loosely coupled solution, which is better for my scenario. Takes less than 30minutes to set it up.
I read into this article:
How to properly configure VPC firewall for App Engine instances?
This was a huge help in getting the firewall setup in the first place - so for those who have found this and are struggling with that - follow along. https://cloud.google.com/appengine/docs/flexible/python/using-shared-vpc is a good reference, as there are some accounts that need permissions "added" to make the magic happen.
My issue - I have two containerized services running in AppEngine one default (website), one API. I've configured the API to run in a VPC/subnet separate from the default created one. I have not made any changes to the firewall settings directly hanging off the App Engine settings as those are global, and do not let you target a specific instance - and the website needs to remain public, while the API should require whitelisting access.
dispatch.yaml for configuring subdomain mapping
dispatch:
- url: "www.example.com/*"
service: default
- url: "api.example.com/*"
service: api
API yaml settings:
network:
name: projects/mycool-12345-project/global/networks/apis
subnetwork_name: apis
instance_tag: myapi
Create a VPC network
name - apis
subnet name - apis
creation mode - automatic
routing mode - regional
dns policy - none
max MTU - 1460
Add firewall rules
allow 130.211.0.0/22, 35.191.0.0/16 port 10402,8443 tag aef-instance priority 1000
deny 0.0.0.0/0 port 8443 tag myapi priority 900
allow 130.211.0.0/22, 35.191.0.0/16 port 8443 tag myapi priority 800
this works - but I cannot specify the "white list IP".
if I do the following and disable the "allow 130 / 35 networks 8443/800"
allow my.ip.number.ihave port 8443 tag myapi priority 800
it never trips this rule, it never recognizes my IP.
what change / how do you configure the firewall in the VPC so it receives the public IP. When I reviewed the logs, it said it denied my request because my IP address was 35.x.x.x.
I would recommend to contact GCP support in that case. If I'm not wrong, you can directly whitelist the IP addresses at App Engine level, but it's not a standard procedure
I'm facing a problem with gcloud and their support can't seem to help me.
So, to put my app in prod I need to use a redis instance to host some data. I'm using memorystore because I like to have everything on gcloud.
My app is in the standard environment on app engine so on their doc (https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-standard) they ask me to configure a VPC connector. But I think that the CIDR that I put is always wrong, can someone help me finding the good CIDR.
connectMode: DIRECT_PEERING
createTime: '2020-03-13T17:20:51.590448560Z'
currentLocationId: europe-west1-d
displayName: APP-EPG
host: 10.240.224.179
locationId: europe-west1-d
memorySizeGb: 1
name: projects/*************/locations/europe-west1/instances/app-epg
persistenceIamIdentity: *************
port: 6379
redisVersion: REDIS_4_0
reservedIpRange: 10.240.224.176/29
state: READY
tier: BASIC
Thank you all !
First in order to VPC connector work yor App Engine instances have to be in the same VPC & region that your Redis instance is. If not there will not be connectivity between the two.
Also make sure you redis and app use one of the approved locations. By now it's a lot of them.
Your redis instance is in europe-west1 region so to create your VPC connector you have to set the name of the VPC network your redis instance is in
(for example "default").
IP range you were asking about is any range (not reserved by the network redis instance is in).
So - for example if your "default" network is 10.13.0.0/28 then you have to specify something else like 10.140.0.0/28 etc. It has to be /29 - otherwise you won't be able to create the connector.
Why 10.13.0.0 or any other addresses ? They are going to be assigned as the source network for you apps to connect to the Redis (or any
other VM's) in the specified network.
I've tested it using the command:
cloud compute networks vpc-access connectors create conn2 --network default /
--range 10.13.0.0/28 --region=europe-west1
Or you can do it using console in Serverless VPC Access and clicking "Add new connector";
You can also read documentation on how to create a connector.
Im writing a NodeJS app and trying to connect to GCPs Redis MemoryStore, but I'm getting the ETIMEDOUT 10.47.29.131:6379 error message. The 10.47.29.131 corresponds to the REDISHOST. I'm trying to reach the server by it's internal private IP.
While the app works locally with a local Redis installed, it does not when deployed to the GCP AppEngine.
My GCP-Setup
Redis instance running at location europe-west3-a
Created a connector under "Serverless VPC access" which is in europe-west3
Redis and the VPC-connector are on the same network "default".
App Engine running in europe-west
Redis isntance:
VPC-connector:
The app.yml
runtime: nodejs
env: flex
automatic_scaling:
// or this but without env: flex (standard)
vpc_access_connector:
name: "projects/project-ID/locations/europe-west/connectors/connector-name"
beta_settings:
cloud_sql_instances: project-ID:europe-west3:name
env_variables:
REDISHOST: '10.47.29.131'
REDISPORT: '6379'
// removed this when trying without env: flex (standard)
network:
name: default
session_affinity: true
I followed these instructions to set everything up: https://cloud.google.com/memorystore/docs/redis/connect-redis-instance-standard
Digging deeper, I found: https://cloud.google.com/vpc/docs/configure-serverless-vpc-access where they mention something about permissions and serverless-vpc-access-images, and while trying to follow the instructions: https://cloud.google.com/compute/docs/images/restricting-image-access#trusted_images I couldn't find "Define trusted image projects." anywhere
What am I missing here?
Well, turns out, the problem was the region I've selected for the Redis instance.
From Documentation:
Important: In order to connect to a Memorystore for Redis instance, the connecting client must be located within the same region as the instance.
A region is a specific geographical location where you can run your resources. Each region is subdivided into several zones.
For example, the us-central1 region in the central United States has zones us-central1-a, us-central1-b, us-central1-c, and us-central1-f.
Althouh the documentation clearly says, that AppEngine and Memorystore have to be in the same region, my assumption on what regions actually are, was false.
When I created the AppEngine, I created it in europe-west, which is the same as europe-west1. On the other hand, when I created the redis instance, I used europe-west3, with the assumption that west3 is the same region as west, which is not.
Since the AppEngines region cannot be changed, I created another redis-instance in europe-west1 and now everything works.
So, the redis region must be exactly the same as the AppEngine region. region1 is the same as region, but region2 or region3 are not the same as region.
I'm using the Managed VM functionality to run a WebSocket server that I'd like to expose to the Internet on any port (preferably port 80) through a URL like: mvm.mydomain.com
I'm not having much success yet.
Here are the relevant parts of various files I'm using to accomplish this:
Dockerfile:
EXPOSE 8080 8081
At the end of the Dockerfile, a Python app is started: it responds to health checks on port 8080 (I can verify this works) and responds to WebSocket requests on port 8081.
app.yaml:
module: mvm
version: 1
runtime: custom
vm: true
api_version: 1
network:
forwarded_ports: ["8081"]
I deploy this app to the cloud using:
$ gcloud preview app deploy .
In the cloud console, I make sure TCP ports 8080 and 8081 are accepted for incoming traffic. I also observe the IP address assigned to the GCE instance (mvm:1) is: x.y.z.z.
$ curl http://x.y.z.z:8080/_ah/health
$ curl http://mvm.my-app-id.appspot.com/_ah/health
Repond both with 200 OK.
Connecting the WebSocket server using some JavaScript works as well:
new WebSocket('ws://x.y.z.z:8081');
So far so good. Except this didn't work (timeout):
new WebSocket('ws://mvm.my-app-id.appspot.com:8081');
I'd like to know why the above WebSocket command doesn't work.
Perhaps something I don't understand in the GAE/GCE port forwarding interaction?
If this could be made to work somehow, I envision the following would be the last steps to finish it.
dispatch.yaml:
dispatch:
# Send all websocket traffic to the ManagedVM module.
- url: "mvm.mydomain.com/*"
module: mvm
I also setup the GAE custom domain CNAME at mvm.mydomain.com.
Connecting the WebSocket server using JavaScript should then work like:
new WebSocket('ws://mvm.mydomain.com:8081');
It may very well be that port forwarding from appspot.com isn't performed, given that prior to the (relatively recent) release of managed VMs, the only traffic that went to appspot.com was on port 80 or 443. I'd suggest using the IP-of-instance method you found to work.
If you don't find that fully satisfying, you should go to the public issue tracker for app engine and post a feature request to have the appspot.com router detect whether a request is heading for a module that corresponds to a managed VM and attempt the port forwarding in that case.
The thing is, putting the raw port on the end of the domain like that means that your browser will use the port you specified as a connection parameter to appspot.com, not as a query param, so appspot.com will have to listen on all ports and redirect if valid. This could be insecure/inefficient, so maybe the port number could be a query param or part of the domain string, similar to how version and module can be specified...
At any rate, given the way in which ports work, I would highly doubt, if your very simple example caused a fail, that app engine's appspot.com domain was even set up to handle port forwarding to managed VM containers at all at present.